|
@@ -0,0 +1,239 @@
|
|
|
+/*
|
|
|
+ * Usrloc module - keepalive
|
|
|
+ *
|
|
|
+ * Copyright (C) 2020 Asipto.com
|
|
|
+ *
|
|
|
+ * This file is part of Kamailio, a free SIP server.
|
|
|
+ *
|
|
|
+ * Kamailio 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
|
|
|
+ *
|
|
|
+ * Kamailio 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, write to the Free Software
|
|
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <time.h>
|
|
|
+#include <sys/time.h>
|
|
|
+
|
|
|
+#include "../../core/dprint.h"
|
|
|
+#include "../../core/ut.h"
|
|
|
+#include "../../core/resolve.h"
|
|
|
+#include "../../core/forward.h"
|
|
|
+#include "../../core/parser/parse_uri.h"
|
|
|
+#include "../../core/parser/parse_from.h"
|
|
|
+#include "../../core/parser/parse_to.h"
|
|
|
+#include "../../core/parser/parse_rr.h"
|
|
|
+
|
|
|
+#include "ul_keepalive.h"
|
|
|
+
|
|
|
+static int ul_ka_send(str *kamsg, dest_info_t *kadst);
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+_KAMETHOD_ _URI_ SIP/2.0\r\n
|
|
|
+Via: SIP/2.0/_PROTO_ _IP_:_PORT_\r\n
|
|
|
+__KAROUTES__
|
|
|
+From: <_KAFROM_>;tag=_KAFROMTAG_\r\n
|
|
|
+To: <sip:_AOR_>\r\n
|
|
|
+Call-ID: _KACALLID_\r\n
|
|
|
+CSeq: 1 _KAMETHOD_\r\n
|
|
|
+Content-Length: 0\r\n\r\n"
|
|
|
+
|
|
|
+*/
|
|
|
+
|
|
|
+#define ULKA_CALLID_PREFIX "ksrulka-"
|
|
|
+#define ULKA_CALLID_PREFIX_LEN (sizeof(ULKA_CALLID_PREFIX) - 1)
|
|
|
+
|
|
|
+#define ULKA_MSG "%.*s %.*s SIP/2.0\r\n" \
|
|
|
+ "Via: SIP/2.0/%.*s %.*s:%.*s;branch=z9hG4bKx.%u.%u.0\r\n" \
|
|
|
+ "%.*s%.*s" \
|
|
|
+ "From: <%.*s>;tag=%.*s-%x-%lx-%x-%x.%x\r\n" \
|
|
|
+ "To: <sip:%.*s%s%.*s>\r\n" \
|
|
|
+ "Call-ID: " ULKA_CALLID_PREFIX "%u.%u\r\n" \
|
|
|
+ "CSeq: 80 %.*s\r\n" \
|
|
|
+ "Content-Length: 0\r\n\r\n"
|
|
|
+
|
|
|
+extern str ul_ka_from;
|
|
|
+extern str ul_ka_domain;
|
|
|
+extern str ul_ka_method;
|
|
|
+extern int ul_ka_mode;
|
|
|
+extern unsigned int nat_bflag;
|
|
|
+
|
|
|
+static unsigned int _ul_ka_counter = 0;
|
|
|
+
|
|
|
+int ul_ka_urecord(urecord_t *ur)
|
|
|
+{
|
|
|
+ ucontact_t *uc;
|
|
|
+#define ULKA_BUF_SIZE 2048
|
|
|
+ char kabuf[ULKA_BUF_SIZE];
|
|
|
+ int kabuf_len;
|
|
|
+ str kamsg;
|
|
|
+ str vaddr;
|
|
|
+ str vport;
|
|
|
+ str sdst = STR_NULL;
|
|
|
+ str sproto = STR_NULL;
|
|
|
+ sip_uri_t duri;
|
|
|
+ char dproto;
|
|
|
+ struct hostent *he;
|
|
|
+ socket_info_t *ssock;
|
|
|
+ dest_info_t idst;
|
|
|
+ unsigned int bcnt = 0;
|
|
|
+ int aortype = 0;
|
|
|
+ int i;
|
|
|
+ struct timeval tv;
|
|
|
+
|
|
|
+ if (ul_ka_mode == 0) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ LM_DBG("keepalive for aor: %.*s\n", ur->aor.len, ur->aor.s);
|
|
|
+
|
|
|
+ for(i=0; i<ur->aor.len; i++) {
|
|
|
+ if(ur->aor.s[i] == '@') {
|
|
|
+ aortype = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _ul_ka_counter++;
|
|
|
+ for (uc = ur->contacts; uc != NULL; uc = uc->next) {
|
|
|
+ if (uc->c.len <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if(ul_ka_mode == 2) {
|
|
|
+ /* keepalive for natted contacts only */
|
|
|
+ if (nat_bflag == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if ((uc->cflags & nat_bflag) != nat_bflag) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(uc->received.len > 0) {
|
|
|
+ sdst = uc->received;
|
|
|
+ } else {
|
|
|
+ if (uc->path.len > 0) {
|
|
|
+ if(get_path_dst_uri(&uc->path, &sdst) < 0) {
|
|
|
+ LM_ERR("failed to get first uri for path\n");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ sdst = uc->c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(parse_uri(sdst.s, sdst.len, &duri) < 0) {
|
|
|
+ LM_ERR("cannot parse next hop uri\n");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(duri.port_no == 0) {
|
|
|
+ duri.port_no = SIP_PORT;
|
|
|
+ }
|
|
|
+ dproto = duri.proto;
|
|
|
+ he = sip_resolvehost(&duri.host, &duri.port_no, &dproto);
|
|
|
+ if(he == NULL) {
|
|
|
+ LM_ERR("can't resolve_host\n");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ init_dest_info(&idst);
|
|
|
+ hostent2su(&idst.to, he, 0, duri.port_no);
|
|
|
+ ssock = uc->sock;
|
|
|
+ if(ssock == NULL) {
|
|
|
+ ssock = get_send_socket(0, &idst.to, dproto);
|
|
|
+ }
|
|
|
+ if(ssock == NULL) {
|
|
|
+ LM_ERR("cannot get sending socket\n");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ idst.proto = dproto;
|
|
|
+ idst.send_sock = ssock;
|
|
|
+
|
|
|
+ if(ssock->useinfo.name.len > 0) {
|
|
|
+ vaddr = ssock->useinfo.name;
|
|
|
+ } else {
|
|
|
+ vaddr = ssock->address_str;
|
|
|
+ }
|
|
|
+ if(ssock->useinfo.port_no > 0) {
|
|
|
+ vport = ssock->useinfo.port_no_str;
|
|
|
+ } else {
|
|
|
+ vport = ssock->port_no_str;
|
|
|
+ }
|
|
|
+ get_valid_proto_string(dproto, 1, 1, &sproto);
|
|
|
+
|
|
|
+ bcnt++;
|
|
|
+ gettimeofday(&tv, NULL);
|
|
|
+ kabuf_len = snprintf(kabuf, ULKA_BUF_SIZE - 1, ULKA_MSG,
|
|
|
+ ul_ka_method.len, ul_ka_method.s,
|
|
|
+ uc->c.len, uc->c.s,
|
|
|
+ sproto.len, sproto.s,
|
|
|
+ vaddr.len, vaddr.s,
|
|
|
+ vport.len, vport.s,
|
|
|
+ _ul_ka_counter, bcnt,
|
|
|
+ (uc->path.len>0)?uc->path.len:0,
|
|
|
+ (uc->path.len>0)?uc->path.s:"",
|
|
|
+ (uc->path.len>0)?2:0,
|
|
|
+ (uc->path.len>0)?"\r\n":"",
|
|
|
+ ul_ka_from.len, ul_ka_from.s,
|
|
|
+ uc->ruid.len, uc->ruid.s, ur->aorhash,
|
|
|
+ tv.tv_sec, tv.tv_usec, _ul_ka_counter, bcnt,
|
|
|
+ ur->aor.len, ur->aor.s,
|
|
|
+ (aortype==1)?"":"@",
|
|
|
+ (aortype==1)?0:ul_ka_domain.len, (aortype==1)?"":ul_ka_domain.s,
|
|
|
+ _ul_ka_counter, bcnt,
|
|
|
+ ul_ka_method.len, ul_ka_method.s);
|
|
|
+ if(kabuf_len<=0 || kabuf_len>=ULKA_BUF_SIZE) {
|
|
|
+ LM_ERR("failed to print the keepalive request\n");
|
|
|
+ } else {
|
|
|
+ LM_DBG("keepalive request (len: %d) [[\n%.*s]]\n",
|
|
|
+ kabuf_len, kabuf_len, kabuf);
|
|
|
+ kamsg.s = kabuf;
|
|
|
+ kamsg.len = kabuf_len;
|
|
|
+ ul_ka_send(&kamsg, &idst);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ul_ka_send(str *kamsg, dest_info_t *kadst)
|
|
|
+{
|
|
|
+ if (kadst->proto == PROTO_UDP) {
|
|
|
+ return udp_send(kadst, kamsg->s, kamsg->len);
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef USE_TCP
|
|
|
+ else if(kadst->proto == PROTO_TCP) {
|
|
|
+ /*tcp*/
|
|
|
+ kadst->id=0;
|
|
|
+ return tcp_send(kadst, 0, kamsg->s, kamsg->len);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#ifdef USE_TLS
|
|
|
+ else if(kadst->proto == PROTO_TLS) {
|
|
|
+ /*tls*/
|
|
|
+ kadst->id=0;
|
|
|
+ return tcp_send(kadst, 0, kamsg->s, kamsg->len);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+#ifdef USE_SCTP
|
|
|
+ else if(kadst->proto == PROTO_SCTP) {
|
|
|
+ /*sctp*/
|
|
|
+ return sctp_core_msg_send(kadst, kamsg->s, kamsg->len);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ else {
|
|
|
+ LM_ERR("unknown proto [%d] for sending keepalive\n",
|
|
|
+ kadst->proto);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+}
|