src/modules/nathelper/sip_pinger.h
e9eea6bc
 /*
61b50e2e
  * Copyright (C) 2005 Voice System SRL
  *
27642a08
  * This file is part of Kamailio, a free SIP server.
61b50e2e
  *
27642a08
  * Kamailio is free software; you can redistribute it and/or modify
61b50e2e
  * 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
  *
27642a08
  * Kamailio is distributed in the hope that it will be useful,
61b50e2e
  * 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
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
61b50e2e
  *
  */
 
 
 #ifndef NATHELPER_OPTIONS_H_
 #define NATHELPER_OPTIONS_H_
 
 #include <stdlib.h>
 #include <string.h>
 
cf83221d
 #include "../../core/parser/parse_rr.h"
 #include "../../core/str.h"
 #include "../../core/ut.h"
 #include "../../core/ip_addr.h"
e98a4ee5
 #include "../../core/rand/kam_rand.h"
61b50e2e
 
 /* size of buffer used for building SIP PING req */
 #define MAX_SIPPING_SIZE 65536
 
 /* helping macros for building SIP PING ping request */
bcc5a668
 #define append_fix(_p, _s)              \
 	do {                                \
 		memcpy(_p, _s, sizeof(_s) - 1); \
 		_p += sizeof(_s) - 1;           \
 	} while(0)
61b50e2e
 
 /* info used to generate SIP ping requests */
bcc5a668
 static int sipping_fromtag = 0;
61b50e2e
 static char sipping_callid_buf[8];
bcc5a668
 static int sipping_callid_cnt = 0;
 static str sipping_callid = {0, 0};
 static str sipping_from = STR_NULL;
 static str sipping_method = str_init("OPTIONS");
61b50e2e
 
 
351fc577
 static void init_sip_ping(void)
61b50e2e
 {
 	int len;
 	char *p;
 
 	/* FROM tag - some random number */
e98a4ee5
 	sipping_fromtag = kam_rand();
61b50e2e
 	/* callid fix part - hexa string */
 	len = 8;
 	p = sipping_callid_buf;
e98a4ee5
 	int2reverse_hex(&p, &len, kam_rand());
61b50e2e
 	sipping_callid.s = sipping_callid_buf;
bcc5a668
 	sipping_callid.len = 8 - len;
61b50e2e
 	/* callid counter part */
e98a4ee5
 	sipping_callid_cnt = kam_rand();
61b50e2e
 }
 
 
 static int sipping_rpl_filter(struct sip_msg *rpl)
 {
bcc5a668
 	struct cseq_body *cseq_b;
61b50e2e
 
 	/* first check number of vias -> must be only one */
bcc5a668
 	if(parse_headers(rpl, HDR_VIA2_F, 0) == -1 || (rpl->via2 != 0))
61b50e2e
 		goto skip;
 
 	/* check the method -> we need CSeq header */
bcc5a668
 	if((!rpl->cseq && parse_headers(rpl, HDR_CSEQ_F, 0) != 0)
 			|| rpl->cseq == 0) {
387847d7
 		LM_ERR("failed to parse CSeq\n");
61b50e2e
 		goto error;
 	}
bcc5a668
 	cseq_b = (struct cseq_body *)rpl->cseq->parsed;
 	if(cseq_b->method.len != sipping_method.len
 			|| strncmp(cseq_b->method.s, sipping_method.s, sipping_method.len)
 					   != 0)
61b50e2e
 		goto skip;
 
 	/* check constant part of callid */
bcc5a668
 	if((!rpl->callid && parse_headers(rpl, HDR_CALLID_F, 0) != 0)
 			|| rpl->callid == 0) {
387847d7
 		LM_ERR("failed to parse Call-ID\n");
61b50e2e
 		goto error;
 	}
bcc5a668
 	if(rpl->callid->body.len <= sipping_callid.len + 1
 			|| strncmp(rpl->callid->body.s, sipping_callid.s,
 					   sipping_callid.len)
 					   != 0
 			|| rpl->callid->body.s[sipping_callid.len] != '-')
61b50e2e
 		goto skip;
 
387847d7
 	LM_DBG("reply for SIP natping filtered\n");
61b50e2e
 	/* it's a reply to a SIP NAT ping -> absorb it and stop any
 	 * further processing of it */
 	return 0;
 skip:
 	return 1;
 error:
 	return -1;
 }
 
 
 /* build the buffer of a SIP ping request */
bcc5a668
 static inline char *build_sipping(str *curi, struct socket_info *s, str *path,
 		str *ruid, unsigned int aorhash, int *len_p)
61b50e2e
 {
bcc5a668
 #define s_len(_s) (sizeof(_s) - 1)
1edb4298
 #define MAX_BRANCHID 9999999
 #define MIN_BRANCHID 1000000
bcc5a668
 #define LEN_BRANCHID \
 	7 /* NOTE: this must be sync with the MX and MIN values !! */
61b50e2e
 	static char buf[MAX_SIPPING_SIZE];
 	char *p;
 	int len;
4da31d56
 	str vaddr;
 	str vport;
 
ade1cad6
 	if(sipping_from.s==NULL || sipping_from.len<=0) {
 		LM_WARN("SIP ping enabled but no SIP ping From address\n");
 		return NULL;
 	}
bcc5a668
 	if(s->useinfo.name.len > 0)
4da31d56
 		vaddr = s->useinfo.name;
 	else
 		vaddr = s->address_str;
 
bcc5a668
 	if(s->useinfo.port_no > 0)
4da31d56
 		vport = s->useinfo.port_no_str;
 	else
 		vport = s->port_no_str;
61b50e2e
 
bcc5a668
 	if(sipping_method.len + 1 + curi->len + s_len(" SIP/2.0" CRLF)
 					+ s_len("Via: SIP/2.0/UDP ") + vaddr.len
 					+ ((s->address.af == AF_INET6) ? 2 : 0) + 1 + vport.len
 					+ s_len(";branch=z9hG4bK") + LEN_BRANCHID
 					+ (path->len ? (s_len(CRLF "Route: ") + path->len) : 0)
 					+ s_len(CRLF "From: ") + sipping_from.len + s_len(";tag=")
 					+ ruid->len + 1 + 8 + 1 + 8 + s_len(CRLF "To: ") + curi->len
 					+ s_len(CRLF "Call-ID: ") + sipping_callid.len + 1 + 8 + 1
 					+ 8 + 1 + s->address_str.len + s_len(CRLF "CSeq: 1 ")
 					+ sipping_method.len
 					+ s_len(CRLF "Content-Length: 0" CRLF CRLF)
 			> MAX_SIPPING_SIZE) {
 		LM_ERR("len exceeds %d\n", MAX_SIPPING_SIZE);
61b50e2e
 		return 0;
 	}
 
 	p = buf;
bcc5a668
 	append_str(p, sipping_method.s, sipping_method.len);
61b50e2e
 	*(p++) = ' ';
bcc5a668
 	append_str(p, curi->s, curi->len);
 	append_fix(p, " SIP/2.0" CRLF "Via: SIP/2.0/UDP ");
 	if(s->address.af == AF_INET6) { /* Via header IP is a IPv6 reference */
 		append_fix(p, "[");
274f1034
 	}
bcc5a668
 	append_str(p, vaddr.s, vaddr.len);
 	if(s->address.af == AF_INET6) {
 		append_fix(p, "]");
274f1034
 	}
61b50e2e
 	*(p++) = ':';
bcc5a668
 	append_str(p, vport.s, vport.len);
 	append_fix(p, ";branch=z9hG4bK");
 	int2bstr((long)(rand() / (float)RAND_MAX * (MAX_BRANCHID - MIN_BRANCHID)
 					 + MIN_BRANCHID),
 			p + LEN_BRANCHID - INT2STR_MAX_LEN + 1, NULL);
1edb4298
 	p += LEN_BRANCHID;
bcc5a668
 	if(path->len) {
 		append_fix(p, CRLF "Route: ");
 		append_str(p, path->s, path->len);
5a57095f
 	}
bcc5a668
 	append_fix(p, CRLF "From: ");
 	append_str(p, sipping_from.s, sipping_from.len);
 	append_fix(p, ";tag=");
 	append_str(p, ruid->s, ruid->len);
ae8f15dc
 	*(p++) = '-';
 	len = 8;
bcc5a668
 	int2reverse_hex(&p, &len, aorhash);
ae8f15dc
 	*(p++) = '-';
61b50e2e
 	len = 8;
bcc5a668
 	int2reverse_hex(&p, &len, sipping_fromtag++);
 	append_fix(p, CRLF "To: ");
 	append_str(p, curi->s, curi->len);
 	append_fix(p, CRLF "Call-ID: ");
 	append_str(p, sipping_callid.s, sipping_callid.len);
61b50e2e
 	*(p++) = '-';
 	len = 8;
bcc5a668
 	int2reverse_hex(&p, &len, sipping_callid_cnt++);
61b50e2e
 	*(p++) = '-';
 	len = 8;
bcc5a668
 	int2reverse_hex(&p, &len, get_ticks());
61b50e2e
 	*(p++) = '@';
bcc5a668
 	append_str(p, s->address_str.s, s->address_str.len);
 	append_fix(p, CRLF "CSeq: 1 ");
 	append_str(p, sipping_method.s, sipping_method.len);
 	append_fix(p, CRLF "Content-Length: 0" CRLF CRLF);
61b50e2e
 
 	*len_p = p - buf;
 	return buf;
 }
 
ade1cad6
 #endif