usrloc: do keepalive mode checks before expire processing
[kamailio] / src / modules / usrloc / ul_keepalive.c
1 /*
2  * Usrloc module - keepalive
3  *
4  * Copyright (C) 2020 Asipto.com
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <sys/time.h>
29
30 #include "../../core/dprint.h"
31 #include "../../core/ut.h"
32 #include "../../core/resolve.h"
33 #include "../../core/forward.h"
34 #include "../../core/globals.h"
35 #include "../../core/pvar.h"
36 #include "../../core/parser/parse_uri.h"
37 #include "../../core/parser/parse_from.h"
38 #include "../../core/parser/parse_to.h"
39 #include "../../core/parser/parse_rr.h"
40
41 #include "ul_keepalive.h"
42
43 extern int ul_keepalive_timeout;
44
45 static int ul_ka_send(str *kamsg, dest_info_t *kadst);
46
47 /**
48  *
49 _KAMETHOD_ _URI_ SIP/2.0\r\n
50 Via: SIP/2.0/_PROTO_ _IP_:_PORT_;branch=z9hG4bKx._GCNT_._BCNT_.0\r\n
51 __KAROUTES__
52 From: <_KAFROM_>;tag=_RUID_-_AORHASH_-_TIMESEC_-_TIMEUSEC_-_GCNT_._BCNT_\r\n
53 To: <sip:_AOR_>\r\n
54 Call-ID: _KACALLID_\r\n
55 CSeq: 1 _KAMETHOD_\r\n
56 Content-Length: 0\r\n\r\n"
57
58 */
59
60 #define ULKA_CALLID_PREFIX "ksrulka-"
61 #define ULKA_CALLID_PREFIX_LEN (sizeof(ULKA_CALLID_PREFIX) - 1)
62
63 #define ULKA_MSG "%.*s %.*s SIP/2.0\r\n" \
64   "Via: SIP/2.0/%.*s %.*s:%.*s;branch=z9hG4bKx.%u.%u.0\r\n" \
65   "%s%.*s%.*s" \
66   "From: <%.*s>;tag=%.*s-%x-%lx-%lx-%x.%x\r\n" \
67   "To: <sip:%.*s%s%.*s>\r\n" \
68   "Call-ID: " ULKA_CALLID_PREFIX "%u.%u\r\n" \
69   "CSeq: 80 %.*s\r\n" \
70   "Content-Length: 0\r\n\r\n"
71
72 extern str ul_ka_from;
73 extern str ul_ka_domain;
74 extern str ul_ka_method;
75 extern int ul_ka_mode;
76 extern int ul_ka_filter;
77 extern int ul_ka_loglevel;
78 extern pv_elem_t *ul_ka_logfmt;
79
80 extern unsigned int ul_nat_bflag;
81
82 static unsigned int _ul_ka_counter = 0;
83
84 /**
85  *
86  */
87 int ul_ka_urecord(urecord_t *ur)
88 {
89         ucontact_t *uc;
90 #define ULKA_BUF_SIZE 2048
91         char kabuf[ULKA_BUF_SIZE];
92         int kabuf_len;
93         str kamsg;
94         str vaddr;
95         str vport;
96         str sdst = STR_NULL;
97         str sproto = STR_NULL;
98         sip_uri_t duri;
99         char dproto;
100         struct hostent *he;
101         socket_info_t *ssock;
102         dest_info_t idst;
103         unsigned int bcnt = 0;
104         int aortype = 0;
105         int i;
106         struct timeval tv;
107         time_t tnow = 0;
108
109         if (ul_ka_mode == ULKA_NONE) {
110                 return 0;
111         }
112         LM_DBG("keepalive for aor: %.*s\n", ur->aor.len, ur->aor.s);
113         tnow = time(NULL);
114
115         for(i=0; i<ur->aor.len; i++) {
116                 if(ur->aor.s[i] == '@') {
117                         aortype = 1;
118                         break;
119                 }
120         }
121         _ul_ka_counter++;
122         for (uc = ur->contacts; uc != NULL; uc = uc->next) {
123                 if (uc->c.len <= 0) {
124                         continue;
125                 }
126                 if((ul_ka_filter&GAU_OPT_SERVER_ID) && (uc->server_id != server_id)) {
127                         continue;
128                 }
129                 if(ul_ka_mode & ULKA_NAT) {
130                         /* keepalive for natted contacts only */
131                         if (ul_nat_bflag == 0) {
132                                 continue;
133                         }
134                         if ((uc->cflags & ul_nat_bflag) != ul_nat_bflag) {
135                                 continue;
136                         }
137                 }
138
139                 if(ul_keepalive_timeout>0 && uc->last_keepalive>0) {
140                         if(uc->last_keepalive+ul_keepalive_timeout < tnow) {
141                                 /* set contact as expired in 10s */
142                                 LM_DBG("set expired contact on keepalive (%u + %u < %u)"
143                                                 " - aor: %.*s c: %.*s\n", (unsigned int)uc->last_keepalive,
144                                                 (unsigned int)ul_keepalive_timeout, (unsigned int)tnow,
145                                                 ur->aor.len, ur->aor.s, uc->c.len, uc->c.s);
146                                 if(uc->expires > tnow + 10) {
147                                         uc->expires = tnow + 10;
148                                         continue;
149                                 }
150                         }
151                 }
152                 if(uc->received.len > 0) {
153                         sdst = uc->received;
154                 } else {
155                         if (uc->path.len > 0) {
156                                 if(get_path_dst_uri(&uc->path, &sdst) < 0) {
157                                         LM_ERR("failed to get first uri for path\n");
158                                         continue;
159                                 }
160                         } else {
161                                 sdst = uc->c;
162                         }
163                 }
164                 if(parse_uri(sdst.s, sdst.len, &duri) < 0) {
165                         LM_ERR("cannot parse next hop uri\n");
166                         continue;
167                 }
168
169                 if(duri.port_no == 0) {
170                         duri.port_no = SIP_PORT;
171                 }
172                 dproto = duri.proto;
173                 he = sip_resolvehost(&duri.host, &duri.port_no, &dproto);
174                 if(he == NULL) {
175                         LM_ERR("cannot resolve destination\n");
176                         continue;
177                 }
178                 if(ul_ka_mode & ULKA_UDP) {
179                         if(dproto != PROTO_UDP) {
180                                 LM_DBG("skipping non-udp contact - proto %d\n", (int)dproto);
181                                 continue;
182                         }
183                 }
184                 init_dest_info(&idst);
185                 hostent2su(&idst.to, he, 0, duri.port_no);
186                 ssock = uc->sock;
187                 if(ssock == NULL) {
188                         ssock = get_send_socket(0, &idst.to, dproto);
189                 }
190                 if(ssock == NULL) {
191                         LM_ERR("cannot get sending socket\n");
192                         continue;
193                 }
194                 idst.proto = dproto;
195                 idst.send_sock = ssock;
196
197                 if(ssock->useinfo.name.len > 0) {
198                         vaddr = ssock->useinfo.name;
199                 } else {
200                         vaddr = ssock->address_str;
201                 }
202                 if(ssock->useinfo.port_no > 0) {
203                         vport = ssock->useinfo.port_no_str;
204                 } else {
205                         vport = ssock->port_no_str;
206                 }
207                 get_valid_proto_string(dproto, 1, 1, &sproto);
208
209                 bcnt++;
210                 gettimeofday(&tv, NULL);
211                 kabuf_len = snprintf(kabuf, ULKA_BUF_SIZE - 1, ULKA_MSG,
212                                 ul_ka_method.len, ul_ka_method.s,
213                                 uc->c.len, uc->c.s,
214                                 sproto.len, sproto.s,
215                                 vaddr.len, vaddr.s,
216                                 vport.len, vport.s,
217                                 _ul_ka_counter, bcnt,
218                                 (uc->path.len>0)?"Route: ":"",
219                                 (uc->path.len>0)?uc->path.len:0,
220                                 (uc->path.len>0)?uc->path.s:"",
221                                 (uc->path.len>0)?2:0,
222                                 (uc->path.len>0)?"\r\n":"",
223                                 ul_ka_from.len, ul_ka_from.s,
224                                 uc->ruid.len, uc->ruid.s, ur->aorhash,
225                                 (unsigned long)tv.tv_sec, (unsigned long)tv.tv_usec,
226                                 _ul_ka_counter, bcnt,
227                                 ur->aor.len, ur->aor.s,
228                                 (aortype==1)?"":"@",
229                                 (aortype==1)?0:ul_ka_domain.len, (aortype==1)?"":ul_ka_domain.s,
230                                 _ul_ka_counter, bcnt,
231                                 ul_ka_method.len, ul_ka_method.s);
232                 if(kabuf_len<=0 || kabuf_len>=ULKA_BUF_SIZE) {
233                         LM_ERR("failed to print the keepalive request\n");
234                 } else {
235                         LM_DBG("keepalive request (len: %d) [[\n%.*s]]\n",
236                                         kabuf_len, kabuf_len, kabuf);
237                         kamsg.s = kabuf;
238                         kamsg.len = kabuf_len;
239                         ul_ka_send(&kamsg, &idst);
240                 }
241
242         }
243         return 0;
244 }
245
246 /**
247  *
248  */
249 static int ul_ka_send(str *kamsg, dest_info_t *kadst)
250 {
251         if (kadst->proto == PROTO_UDP) {
252                 return udp_send(kadst, kamsg->s, kamsg->len);
253         }
254
255 #ifdef USE_TCP
256         else if(kadst->proto == PROTO_TCP) {
257                 /*tcp*/
258                 kadst->id=0;
259                 return tcp_send(kadst, 0, kamsg->s, kamsg->len);
260         }
261 #endif
262 #ifdef USE_TLS
263         else if(kadst->proto == PROTO_TLS) {
264                 /*tls*/
265                 kadst->id=0;
266                 return tcp_send(kadst, 0, kamsg->s, kamsg->len);
267         }
268 #endif
269 #ifdef USE_SCTP
270         else if(kadst->proto == PROTO_SCTP) {
271                 /*sctp*/
272                 return sctp_core_msg_send(kadst, kamsg->s, kamsg->len);
273         }
274 #endif
275         else {
276                 LM_ERR("unknown proto [%d] for sending keepalive\n",
277                                 kadst->proto);
278                 return -1;
279         }
280 }
281
282 /**
283  *
284  */
285 unsigned long ul_ka_fromhex(str *shex, int *err)
286 {
287     unsigned long v = 0;
288         int i;
289
290         *err = 0;
291     for (i=0; i<shex->len; i++) {
292         char b = shex->s[i];
293         if (b >= '0' && b <= '9') b = b - '0';
294         else if (b >= 'a' && b <='f') b = b - 'a' + 10;
295         else if (b >= 'A' && b <='F') b = b - 'A' + 10;
296                 else { *err = 1; return 0; };
297         v = (v << 4) | (b & 0xF);
298     }
299     return v;
300 }
301
302 /**
303  *
304  */
305 int ul_ka_reply_received(sip_msg_t *msg)
306 {
307         to_body_t *fb;
308         str ruid;
309         str tok;
310         int err;
311         unsigned int aorhash;
312         char *p;
313         struct timeval tvm;
314         struct timeval tvn;
315         unsigned int tvdiff;
316
317         if(msg->cseq == NULL) {
318                 if((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || (msg->cseq == NULL)) {
319                         LM_ERR("invalid CSeq header\n");
320                         return -1;
321                 }
322         }
323
324         if(get_cseq(msg)->method.len != ul_ka_method.len) {
325                 return 1;
326         }
327         if(strncmp(get_cseq(msg)->method.s, ul_ka_method.s, ul_ka_method.len) != 0) {
328                 return 1;
329         }
330
331         /* there must be no second via */
332         if(!(parse_headers(msg, HDR_VIA2_F, 0) == -1 || (msg->via2 == 0)
333                            || (msg->via2->error != PARSE_OK))) {
334                 return 1;
335         }
336
337         /* from uri check */
338         if((parse_from_header(msg)) < 0) {
339                 LM_ERR("cannot parse From header\n");
340                 return -1;
341         }
342
343         fb = get_from(msg);
344         if(fb->uri.len != ul_ka_from.len
345                         || strncmp(fb->uri.s, ul_ka_from.s, ul_ka_from.len) != 0) {
346                 return 1;
347         }
348
349         /* from-tag is: ruid-aorhash-tmsec-tmusec-counter */
350         if(fb->tag_value.len <= 8) {
351                 return 1;
352         }
353
354         LM_DBG("checking keepalive reply [%.*s]\n", fb->tag_value.len,
355                         fb->tag_value.s);
356
357         /* todo: macro/function to tokenize */
358         /* skip counter */
359         p = q_memrchr(fb->tag_value.s, '-', fb->tag_value.len);
360         if(p == NULL) {
361                 LM_DBG("from tag format mismatch [%.*s]\n", fb->tag_value.len,
362                                 fb->tag_value.s);
363                 return 1;
364         }
365
366         /* tv_usec hash */
367         tok.len = p - fb->tag_value.s;
368         p = q_memrchr(fb->tag_value.s, '-', tok.len);
369         if(p == NULL) {
370                 LM_DBG("from tag format mismatch [%.*s]\n", fb->tag_value.len,
371                                 fb->tag_value.s);
372                 return 1;
373         }
374         tok.s = p + 1;
375         tok.len = fb->tag_value.s + tok.len - tok.s;
376         if(tok.len <= 0) {
377                 LM_DBG("empty token\n");
378                 return 1;
379         }
380         LM_DBG("tv usec string is [%.*s] (%d)\n", tok.len, tok.s, tok.len);
381         tvm.tv_usec = ul_ka_fromhex(&tok, &err);
382         if(err==1) {
383                 LM_DBG("invalid tv usec value\n");
384                 return 1;
385         }
386         LM_DBG("tv usec is [%lu]\n", (unsigned long)tvm.tv_usec);
387
388         /* tv_sec hash */
389         tok.len = p - fb->tag_value.s;
390         p = q_memrchr(fb->tag_value.s, '-', tok.len);
391         if(p == NULL) {
392                 LM_DBG("from tag format mismatch [%.*s]\n", fb->tag_value.len,
393                                 fb->tag_value.s);
394                 return 1;
395         }
396         tok.s = p + 1;
397         tok.len = fb->tag_value.s + tok.len - tok.s;
398         if(tok.len <= 0) {
399                 LM_DBG("empty token\n");
400                 return 1;
401         }
402         LM_DBG("tv sec string is [%.*s] (%d)\n", tok.len, tok.s, tok.len);
403         tvm.tv_sec = ul_ka_fromhex(&tok, &err);
404         if(err==1) {
405                 LM_DBG("invalid tv sec value\n");
406                 return 1;
407         }
408         LM_DBG("tv sec is [%lu]\n", (unsigned long)tvm.tv_sec);
409
410         /* aor hash */
411         tok.len = p - fb->tag_value.s;
412         p = q_memrchr(fb->tag_value.s, '-', tok.len);
413         if(p == NULL) {
414                 LM_DBG("from tag format mismatch [%.*s]\n", fb->tag_value.len,
415                                 fb->tag_value.s);
416                 return 1;
417         }
418         tok.s = p + 1;
419         tok.len = fb->tag_value.s + tok.len - tok.s;
420         if(tok.len <= 0) {
421                 LM_DBG("empty token\n");
422                 return 1;
423         }
424         LM_DBG("aor hash string is [%.*s] (%d)\n", tok.len, tok.s, tok.len);
425         aorhash = ul_ka_fromhex(&tok, &err);
426         if(err==1) {
427                 LM_DBG("invalid aor hash value\n");
428                 return 1;
429         }
430         LM_DBG("aor hash is [%u]\n", aorhash);
431
432         ruid.s = fb->tag_value.s;
433         ruid.len = tok.s - ruid.s - 1;
434
435         if(ruid.len <= 0) {
436                 LM_DBG("cannot get ruid in [%.*s]\n", fb->tag_value.len,
437                                 fb->tag_value.s);
438                 return 1;
439         }
440
441         gettimeofday(&tvn, NULL);
442         tvdiff = (tvn.tv_sec - tvm.tv_sec) * 1000000
443                                         + (tvn.tv_usec - tvm.tv_usec);
444         ul_update_keepalive(aorhash, &ruid, tvn.tv_sec, tvdiff);
445
446         if(ul_ka_loglevel != 255 && ul_ka_logfmt != NULL) {
447                 if (pv_printf_s(msg, ul_ka_logfmt, &tok) == 0) {
448                         LOG(ul_ka_loglevel, "keepalive roundtrip: %u.%06u sec - ruid [%.*s]%.*s\n",
449                                         tvdiff/1000000, tvdiff%1000000, ruid.len, ruid.s,
450                                         tok.len, tok.s);
451                         return 0;
452                 }
453         }
454
455         LM_DBG("response of keepalive for ruid [%.*s] aorhash [%u] roundtrip: %u.%06u secs\n",
456                         ruid.len, ruid.s, aorhash, tvdiff/1000000, tvdiff%1000000);
457
458         return 0;
459 }