00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
00046
00047
00048 int ping_nated_only = 0;
00049
00050
00051
00052
00053
00054
00055 int natping_crlf = 1;
00056
00057
00058
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
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
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
00104 if (load_tm(&tmb) == -1)
00105 return -1;
00106 }
00107
00108
00109
00110
00111
00112 if (dont_fork) {
00113 register_timer(natping, NULL, natping_interval);
00114 } else {
00115 register_procs(1);
00116
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
00144 if (dont_fork)
00145 return 0;
00146
00147
00148
00149
00150
00151 if ((rank != PROC_MAIN) || (natping_interval == 0))
00152 return 0;
00153
00154
00155
00156
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
00166 if (cfg_child_init()) return -1;
00167
00168 natping_cycle();
00169
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);
00189 for(;;) {
00190 sleep(natping_interval);
00191
00192
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
00215
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;
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
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
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
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 + params->uri.len + 1 +
00289 SIP_VERSION_LEN + CRLF_LEN + via.len +
00290 PING_FROM_LEN + 1 +
00291 params->from_uri.len + PING_FROMTAG_LEN +
00292 CRLF_LEN + PING_TO_LEN + 1 + params->to_uri.len + CRLF_LEN +
00293 PING_CALLID_LEN + 1 + callid_str.len + CRLF_LEN +
00294 PING_CSEQ_LEN + 1 + 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
00303 t = msg;
00304
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
00318 memcpy(t, via.s, via.len);
00319 t += via.len;
00320
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
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
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
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
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
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";
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
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";
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
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
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
00517 return 0;
00518 }
00519 return 1;
00520 }