1 /*
2  * Copyright (C) 2006 Otmar Lendl & Klaus Darilion
3  *
4  * Based on the ENUM and domain module.
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  * History:
23  * --------
24  *  2006-04-20  Initial Version
25  *  2006-09-08  Updated to -02 version, added support for D2P+SIP:std
26  */
27 
28 
29 /*!
30  * \file
31  * \brief Domain Policy related functions
32  */
33 
34 
35 #include "domainpolicy_mod.h"
36 #include "domainpolicy.h"
37 #include "../../lib/srdb1/db.h"
38 #include "../../core/parser/parse_uri.h"
39 #include "../../core/parser/parse_from.h"
40 #include "../../core/ut.h"
41 #include "../../core/dset.h"
42 #include "../../core/route.h"
43 #include "../../core/ip_addr.h"
44 #include "../../core/socket_info.h"
45 
46 #include "../../core/resolve.h"
47 #include "../../core/strutils.h"
48 
49 #define IS_D2PNAPTR(naptr) ((naptr->services_len >= 7) && (!strncasecmp("D2P+SIP", naptr->services, 7)))
50 
51 static db1_con_t* db_handle=0;
52 static db_func_t domainpolicy_dbf;
53 
54 /*
55  * some helper structs + functions to help build up the AVPs.
56  * We can't immediately store them in AVPs as a later non-matched
57  * rule can result in junking all the AVPs added up to that moment.
58  *
59  * Thus we store them temporarily in an avp_stack.
60  */
61 #define AVPMAXSIZE 120
62 #define AVPSTACKSIZE 32
63 
64 struct avp {
65     char att[AVPMAXSIZE];
66     char val[AVPMAXSIZE];
67 };
68 
69 struct avp_stack {
70     int succeeded;
71     int i;
72     struct avp avp[AVPSTACKSIZE];
73 };
74 
75 /*
76  * Push avp-pair on stack.
77  *
78  * return 0 on failure.
79  */
stack_push(struct avp_stack * stack,char * att,char * val)80 static int stack_push(struct avp_stack *stack, char *att, char *val) {
81     int i;
82     if (stack->i >= (AVPSTACKSIZE-1)) {
83 	LM_ERR("exceeded stack size.!\n");
84 	return(0);
85     }
86 
87     i = (stack->i)++;
88     strncpy(stack->avp[i].att, att, AVPMAXSIZE - 1);
89     strncpy(stack->avp[i].val, val, AVPMAXSIZE - 1);
90 
91     stack->succeeded = 1;
92 
93     return(1);
94 }
95 
96 
stack_reset(struct avp_stack * stack)97 static void stack_reset(struct avp_stack *stack) {
98     stack->i 		= 0;
99     stack->succeeded	= 0;
100 }
101 
stack_succeeded(struct avp_stack * stack)102 static int stack_succeeded(struct avp_stack *stack) {
103     return(stack->succeeded);
104 }
105 
stack_to_avp(struct avp_stack * stack)106 static void stack_to_avp(struct avp_stack *stack) {
107 	int j;
108 	int_str  avp_att;
109 	int_str  avp_val;
110 	unsigned int intval;
111 
112 	intval=2;
113 
114 	for(j=0; j< stack->i; j++) {
115 		/* AVP names can be integer or string based */
116 		LM_DBG("process AVP: name='%s' value='%s'\n",
117 					stack->avp[j].att, stack->avp[j].val);
118 
119 		/* if the second character is a ':', ignore the prefix
120 		 * this allows specifying the name with i:... or s:... too
121 		 * Note: the first character is ignored!!!
122 		 */
123 		if ( stack->avp[j].att[0] && stack->avp[j].att[1]==':' ) {
124 
125 			switch (stack->avp[j].att[0]) {
126 			case 'i':
127 			case 'I':
128 				intval = 1;
129 				break;
130 			case 's':
131 			case 'S':
132 				intval = 0;
133 				break;
134 			default:
135 				LM_ERR("invalid type '%c'\n",stack->avp[j].att[0]);
136 				continue;
137 			}
138 			avp_att.s.s = (char *) &(stack->avp[j].att[2]);
139 		} else {
140 			avp_att.s.s = stack->avp[j].att;
141 		}
142 		avp_att.s.len = strlen(avp_att.s.s);
143 		if (!avp_att.s.len) {
144 			LM_ERR("empty AVP name string!\n");
145 			continue;
146 		}
147 
148 		avp_val.s.s = stack->avp[j].val;
149 		avp_val.s.len = strlen(avp_val.s.s);
150 
151 		if (intval==1) {
152 			/* integer type explicitely forced with i: */
153 			if (str2int(&(avp_att.s), &intval) == 0) {
154 				/* integer named AVP */
155 				if (!intval) {
156 					LM_ERR("nameless integer AVP!\n");
157 					continue;
158 				}
159 				avp_att.n = intval;
160 				LM_DBG("create integer named AVP <i:%d>\n", avp_att.n);
161 				add_avp(AVP_VAL_STR, avp_att, avp_val);
162 				continue;
163 			} else {
164 				LM_ERR("integer AVP is not an integer!\n");
165 				continue;
166 			}
167 		}
168 
169 		if (intval==2) {
170 			/* string type undefined */
171 			/* convert name into integer. if it succeeds then it is
172 			 * an integer named AVP. If it fails, then it is a string
173 			 * named AVP
174 			 */
175 			if (str2int(&(avp_att.s), &intval) == 0) {
176 				/* integer named AVP */
177 				if (!intval) {
178 					LM_ERR("nameless integer AVP!\n");
179 					continue;
180 				}
181 				avp_att.n = intval;
182 				LM_DBG("create integer named AVP <i:%d>\n", avp_att.n);
183 				add_avp(AVP_VAL_STR, avp_att, avp_val);
184 				continue;
185 			} else {
186 				LM_DBG("create string named AVP <s:%.*s>\n",
187 						avp_att.s.len, ZSW(avp_att.s.s));
188 				add_avp(AVP_NAME_STR | AVP_VAL_STR, avp_att, avp_val);
189 				continue;
190 			}
191 		}
192 
193 		/* intval==0, string type explicitely forced with s: */
194 		LM_DBG("create string named AVP <s:%.*s>\n",
195 				avp_att.s.len, ZSW(avp_att.s.s));
196 		add_avp(AVP_NAME_STR | AVP_VAL_STR, avp_att, avp_val);
197 	}
198 }
199 
200 /* helper db functions*/
201 
202 /*!
203  * \brief Bind the database interface
204  * \param db_url database url
205  * \return -1 on failure, 0 on success
206  */
domainpolicy_db_bind(const str * db_url)207 int domainpolicy_db_bind(const str* db_url)
208 {
209 	if (db_bind_mod(db_url, &domainpolicy_dbf )) {
210 		LM_CRIT("cannot bind to database module! "
211 		"Did you forget to load a database module ?\n");
212 		return -1;
213 	}
214 	return 0;
215 }
216 
217 
218 /*!
219  * \brief Initialize the database connection
220  * \param db_url database url
221  * \return -1 on failure, 0 on success
222  */
domainpolicy_db_init(const str * db_url)223 int domainpolicy_db_init(const str* db_url)
224 {
225 	if (domainpolicy_dbf.init==0){
226 		LM_CRIT("unbound database module\n");
227 		goto error;
228 	}
229 	db_handle=domainpolicy_dbf.init(db_url);
230 	if (db_handle==0){
231 		LM_CRIT("cannot initialize database connection\n");
232 		goto error;
233 	}
234 	return 0;
235 error:
236 	return -1;
237 }
238 
239 
240 /*!
241  * \brief Close the database connection
242  */
domainpolicy_db_close(void)243 void domainpolicy_db_close(void)
244 {
245 	if (db_handle && domainpolicy_dbf.close){
246 		domainpolicy_dbf.close(db_handle);
247 		db_handle=0;
248 	}
249 }
250 
251 
252 /*!
253  * \brief Check the database table version
254  * \param db_url database URL
255  * \return -1 on failure, 0 on success
256  */
domainpolicy_db_ver(const str * db_url)257 int domainpolicy_db_ver(const str* db_url)
258 {
259 	db1_con_t* dbh;
260 
261 	if (domainpolicy_dbf.init==0){
262 		LM_CRIT("unbound database\n");
263 		return -1;
264 	}
265 	dbh=domainpolicy_dbf.init(db_url);
266 	if (dbh==0){
267 		LM_CRIT("null database handler\n");
268 		return -1;
269 	}
270 	if (db_check_table_version(&domainpolicy_dbf, dbh, &domainpolicy_table, DOMAINPOLICY_TABLE_VERSION) < 0) {
271 		DB_TABLE_VERSION_ERROR(domainpolicy_table);
272 		domainpolicy_dbf.close(dbh);
273 		dbh=0;
274 		return -1;
275 	}
276 	domainpolicy_dbf.close(dbh);
277 	dbh=0;
278 	return 0;
279 }
280 
281 /***************************/
282 /*
283  *
284  * code from enum.c
285  *
286  * should be moved to some DDDS support module instead of code-duplication
287  *
288  *
289  */
290 
291 /* Parse NAPTR regexp field of the form !pattern!replacement! and return its
292  * components in pattern and replacement parameters.  Regexp field starts at
293  * address first and is len characters long.
294  */
parse_naptr_regexp(char * first,int len,str * pattern,str * replacement)295 static inline int parse_naptr_regexp(char* first, int len, str* pattern,
296 										str* replacement)
297 {
298 	char *second, *third;
299 
300 	if (len > 0) {
301 		if (*first == '!') {
302 			second = (char *)memchr((void *)(first + 1), '!', len - 1);
303 			if (second) {
304 				len = len - (second - first + 1);
305 				if (len > 0) {
306 					third = memchr(second + 1, '!', len);
307 					if (third) {
308 						pattern->len = second - first - 1;
309 						pattern->s = first + 1;
310 						replacement->len = third - second - 1;
311 						replacement->s = second + 1;
312 						return 1;
313 					} else {
314 						LM_ERR("third ! missing from regexp\n");
315 						return -1;
316 					}
317 				} else {
318 					LM_ERR("third ! missing from regexp\n");
319 					return -2;
320 				}
321 			} else {
322 				LM_ERR("second ! missing from regexp\n");
323 				return -3;
324 			}
325 		} else {
326 			LM_ERR("first ! missing from regexp\n");
327 			return -4;
328 		}
329 	} else {
330 		LM_ERR("regexp missing\n");
331 		return -5;
332 	}
333 }
334 
335 
336 /*
337  * Tests if one result record is "greater" that the other.  Non-NAPTR records
338  * greater that NAPTR record.  An invalid NAPTR record is greater than a
339  * valid one.  Valid NAPTR records are compared based on their
340  * (order,preference).
341  *
342  * Naptrs without D2P+SIP service field are greater.
343  *
344  */
naptr_greater(struct rdata * a,struct rdata * b)345 static inline int naptr_greater(struct rdata* a, struct rdata* b)
346 {
347 	struct naptr_rdata *na, *nb;
348 
349 	if (a->type != T_NAPTR) return 1;
350 	if (b->type != T_NAPTR) return 0;
351 
352 	na = (struct naptr_rdata*)a->rdata;
353 	if (na == 0) return 1;
354 
355 	nb = (struct naptr_rdata*)b->rdata;
356 	if (nb == 0) return 0;
357 
358 	if (!IS_D2PNAPTR(na))
359 	    	return 1;
360 
361 	if (!IS_D2PNAPTR(nb))
362 	    	return 0;
363 
364 
365 	return (((na->order) << 16) + na->pref) >
366 		(((nb->order) << 16) + nb->pref);
367 }
368 
369 
370 /*
371  * Bubble sorts result record list according to naptr (order,preference).
372  */
naptr_sort(struct rdata ** head)373 static inline void naptr_sort(struct rdata** head)
374 {
375 	struct rdata *p, *q, *r, *s, *temp, *start;
376 
377         /* r precedes p and s points to the node up to which comparisons
378          are to be made */
379 
380 	s = NULL;
381 	start = *head;
382 	while ( s != start -> next ) {
383 		r = p = start ;
384 		q = p -> next ;
385 		while ( p != s ) {
386 			if ( naptr_greater(p, q) ) {
387 				if ( p == start ) {
388 					temp = q -> next ;
389 					q -> next = p ;
390 					p -> next = temp ;
391 					start = q ;
392 					r = q ;
393 				} else {
394 					temp = q -> next ;
395 					q -> next = p ;
396 					p -> next = temp ;
397 					r -> next = q ;
398 					r = q ;
399 				}
400 			} else {
401 				r = p ;
402 				p = p -> next ;
403 			}
404 			q = p -> next ;
405 			if ( q == s ) s = p ;
406 		}
407 	}
408 	*head = start;
409 }
410 
411 /*
412  * input: rule straight from the DDDS + avp-stack.
413  *
414  * output: adds found rules to the stack and return
415  * 	1 on success
416  * 	0 on failure
417  */
check_rule(str * rule,char * service,int service_len,struct avp_stack * stack)418 static int check_rule(str *rule, char *service, int service_len, struct avp_stack *stack) {
419 
420     /* for the select */
421     db_key_t keys[2];
422     db_val_t vals[2];
423     db_key_t cols[4];
424     db1_res_t* res;
425     db_row_t* row;
426     db_val_t* val;
427     int	i;
428     char *type;
429     int type_len;
430 
431     LM_INFO("checking for '%.*s'.\n", rule->len, ZSW(rule->s));
432 
433     if ((service_len != 11) || (strncasecmp("d2p+sip:fed", service, 11) &&
434 	    strncasecmp("d2p+sip:std", service, 11)  && strncasecmp("d2p+sip:dom", service, 11))) {
435     	LM_ERR("can only cope with d2p+sip:fed, d2p+sip:std,and d2p+sip:dom "
436 				"for now (and not %.*s).\n", service_len, service);
437 	return(0);
438     }
439 
440     type = service + 8;
441     type_len = service_len - 8;
442 
443     if (domainpolicy_dbf.use_table(db_handle, &domainpolicy_table) < 0) {
444 	    LM_ERR("failed to domainpolicy table\n");
445 	    return -1;
446     }
447 
448     keys[0]=&domainpolicy_col_rule;
449     keys[1]=&domainpolicy_col_type;
450     cols[0]=&domainpolicy_col_rule;
451     cols[1]=&domainpolicy_col_type;
452     cols[2]=&domainpolicy_col_att;
453     cols[3]=&domainpolicy_col_val;
454 
455     VAL_TYPE(&vals[0]) = DB1_STR;
456     VAL_NULL(&vals[0]) = 0;
457     VAL_STR(&vals[0]).s = rule->s;
458     VAL_STR(&vals[0]).len = rule->len;
459 
460     VAL_TYPE(&vals[1]) = DB1_STR;
461     VAL_NULL(&vals[1]) = 0;
462     VAL_STR(&vals[1]).s = type;
463     VAL_STR(&vals[1]).len = type_len;
464 
465     /*
466      * SELECT rule, att, val from domainpolicy where rule = "..."
467      */
468 
469     if (domainpolicy_dbf.query(db_handle, keys, 0, vals, cols, 2, 4, 0, &res) < 0
470 		    ) {
471 	    LM_ERR("querying database\n");
472 	    return -1;
473     }
474 
475     LM_INFO("querying database OK\n");
476 
477     if (RES_ROW_N(res) == 0) {
478 	    LM_DBG("rule '%.*s' is not know.\n",
479 		rule->len, ZSW(rule->s));
480 	    domainpolicy_dbf.free_result(db_handle, res);
481 	    return 0;
482     } else {
483 	    LM_DBG("rule '%.*s' is known\n", rule->len, ZSW(rule->s));
484 
485 	    row = RES_ROWS(res);
486 
487 	    for(i = 0; i < RES_ROW_N(res); i++) {
488 			if (ROW_N(row + i) != 4) {
489 	    	    LM_ERR("unexpected cell count\n");
490 				return(-1);
491 			}
492 
493 			val = ROW_VALUES(row + i);
494 
495 			if ((VAL_TYPE(val) != DB1_STRING) ||
496 				(VAL_TYPE(val+1) != DB1_STRING) ||
497 				(VAL_TYPE(val+2) != DB1_STRING) ||
498 				(VAL_TYPE(val+3) != DB1_STRING)) {
499 					LM_ERR("unexpected cell types\n");
500 			    return(-1);
501 			}
502 
503 			if (VAL_NULL(val+2) || VAL_NULL(val+3)) {
504 				LM_INFO("db returned NULL values. Fine with us.\n");
505 				continue;
506 			}
507 
508 			LM_INFO("DB returned %s/%s \n",VAL_STRING(val+2),VAL_STRING(val+3));
509 
510 
511 			if (!stack_push(stack, (char *) VAL_STRING(val+2),
512 					(char *) VAL_STRING(val+3))) {
513 			    return(-1);
514 			}
515 	    }
516 	    domainpolicy_dbf.free_result(db_handle, res);
517 	    return 1;
518     }
519 }
520 
dp_can_connect_str(str * domain,int rec_level)521 int dp_can_connect_str(str *domain, int rec_level) {
522     struct rdata* head;
523     struct rdata* l;
524     struct naptr_rdata* naptr;
525     struct naptr_rdata* next_naptr;
526     int	   ret;
527     str	   newdomain;
528     char   uri[MAX_URI_SIZE];
529     struct avp_stack stack;
530     int    last_order = -1;
531     int    failed = 0;
532     int    found_anything = 0;
533 
534     str pattern, replacement, result;
535 
536     stack_reset(&stack);
537     /* If we're in a recursive call, set the domain-replacement */
538     if ( rec_level > 0 ) {
539 	stack_push(&stack, domain_replacement_name.s.s, domain->s);
540 	stack.succeeded = 0;
541     }
542 
543     if (rec_level > MAX_DDDS_RECURSIONS) {
544     	LM_ERR("too many indirect NAPTRs. Aborting at %.*s.\n", domain->len,
545 				ZSW(domain->s));
546 		return(DP_DDDS_RET_DNSERROR);
547     }
548 
549     LM_INFO("looking up Domain itself: %.*s\n",domain->len, ZSW(domain->s));
550     ret = check_rule(domain,"D2P+sip:dom", 11, &stack);
551 
552     if (ret == 1) {
553 	LM_INFO("found a match on domain itself\n");
554 	stack_to_avp(&stack);
555 	return(DP_DDDS_RET_POSITIVE);
556     } else if (ret == 0) {
557 	LM_INFO("no match on domain itself.\n");
558 	stack_reset(&stack);
559 	/* If we're in a recursive call, set the domain-replacement */
560 	if ( rec_level > 0 ) {
561 	    stack_push(&stack, domain_replacement_name.s.s, (char *) domain->s);
562 	    stack.succeeded = 0;
563 	}
564     } else {
565 	return(DP_DDDS_RET_DNSERROR);	/* actually: DB error */
566     }
567 
568     LM_INFO("doing DDDS with %.*s\n",domain->len, ZSW(domain->s));
569     head = get_record(domain->s, T_NAPTR, RES_ONLY_TYPE);
570     if (head == 0) {
571     	LM_NOTICE("no NAPTR record found for %.*s.\n",
572 				domain->len, ZSW(domain->s));
573     	return(DP_DDDS_RET_NOTFOUND);
574     }
575 
576     LM_DBG("found the following NAPTRs: \n");
577     for (l = head; l; l = l->next) {
578 	if (l->type != T_NAPTR) {
579 	    LM_DBG("found non-NAPTR record.\n");
580 	    continue; /*should never happen*/
581 	}
582 	naptr = (struct naptr_rdata*)l->rdata;
583 	if (naptr == 0) {
584 		LM_CRIT("null rdata\n");
585 		continue;
586 	}
587 	LM_DBG("order %u, pref %u, flen %u, flags '%.*s', slen %u, "
588 	    "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n",
589 		naptr->order, naptr->pref,
590 	    naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
591 	    naptr->services_len,
592 	    (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
593 	    (int)(naptr->regexp_len), ZSW(naptr->regexp),
594 	    ZSW(naptr->repl)
595 	    );
596     }
597 
598 
599     LM_DBG("sorting...\n");
600     naptr_sort(&head);
601 
602     for (l = head; l; l = l->next) {
603 
604 	if (l->type != T_NAPTR) continue; /*should never happen*/
605 	naptr = (struct naptr_rdata*)l->rdata;
606 	if (naptr == 0) {
607 		LM_CRIT("null rdata\n");
608 		continue;
609 	}
610 
611 	LM_DBG("considering order %u, pref %u, flen %u, flags '%.*s', slen %u, "
612 	    "services '%.*s', rlen %u, regexp '%.*s', repl '%s'\n",
613 		naptr->order, naptr->pref,
614 	    naptr->flags_len, (int)(naptr->flags_len), ZSW(naptr->flags),
615 	    naptr->services_len,
616 	    (int)(naptr->services_len), ZSW(naptr->services), naptr->regexp_len,
617 	    (int)(naptr->regexp_len), ZSW(naptr->regexp),
618 	    ZSW(naptr->repl)
619 	    );
620 
621 	/*
622 	 * New order? then we check whether the had success during the last one.
623 	 * If yes, we can leave the loop.
624 	 */
625 	if (last_order != naptr->order) {
626 	    	last_order = naptr->order;
627 		failed = 0;
628 
629 		if (stack_succeeded(&stack)) {
630     		LM_INFO("we don't need to consider further orders "
631 						"(starting with %d).\n",last_order);
632 		    break;
633 		}
634 	} else if (failed) {
635 	    LM_INFO("order %d has already failed.\n",last_order);
636 	    continue;
637 	}
638 
639 
640 	/*
641 	 * NAPTRs we don't care about
642 	 */
643 	if (!IS_D2PNAPTR(naptr))
644 	    continue;
645 
646 	/*
647 	 * once we've been here, don't return DP_DDDS_RET_NOTFOUND
648 	 */
649 	found_anything = 1;
650 
651 	next_naptr = NULL;
652 	if (l->next && (l->next->type == T_NAPTR)) {
653 	     next_naptr = (struct naptr_rdata*)l->next->rdata;
654 	}
655 
656 	/*
657 	 * Non-terminal?
658 	 */
659 	if ((naptr->services_len == 7) && !strncasecmp("D2P+SIP", naptr->services,7) && (naptr->flags_len == 0)){
660 	    LM_INFO("found non-terminal NAPTR\n");
661 
662 	    /*
663 	     * This needs to be the only record with this order.
664 	     */
665 	    if (next_naptr && (next_naptr->order == naptr->order) && IS_D2PNAPTR(next_naptr)) {
666 	    	LM_ERR("non-terminal NAPTR needs to be the only one "
667 					"with this order %.*s.\n", domain->len, ZSW(domain->s));
668 
669 		return(DP_DDDS_RET_DNSERROR);
670 	    }
671 
672 	    newdomain.s = naptr->repl;
673 	    newdomain.len = strlen(naptr->repl);
674 
675 	    ret = dp_can_connect_str(&newdomain, rec_level + 1);
676 
677 	    if (ret == DP_DDDS_RET_POSITIVE)	/* succeeded, we're done. */
678 		return(ret);
679 
680 	    if (ret == DP_DDDS_RET_NEGATIVE)	/* found rules, did not work */
681 		continue;			/* look for more rules */
682 
683 	    if (ret == DP_DDDS_RET_DNSERROR)	/* errors during lookup */
684 		return(ret);			/* report them */
685 
686 	    if (ret == DP_DDDS_RET_NOTFOUND)	/* no entries in linked domain? */
687 		return(ret);			/* ok, fine. go with that */
688 
689 	    continue; /* not reached */
690 	}
691 
692 	/*
693 	 * wrong kind of terminal
694 	 */
695 	if ((naptr->flags_len != 1) || (tolower(naptr->flags[0]) != 'u')) {
696 	    LM_ERR("terminal NAPTR needs flag = 'u' and not '%.*s'.\n",
697 					(int)naptr->flags_len, ZSW(naptr->flags));
698 		/*
699 		 * It's not that clear what we should do now: Ignore this records or regard it as failed.
700 		 * We go with "ignore" for now.
701 		 */
702 		continue;
703 	}
704 
705 	if (parse_naptr_regexp(&(naptr->regexp[0]), naptr->regexp_len,
706 			       &pattern, &replacement) < 0) {
707 		LM_ERR("parsing of NAPTR regexp failed\n");
708 		continue;
709 	}
710 	result.s = &(uri[0]);
711 	result.len = MAX_URI_SIZE;
712 
713 	/* Avoid making copies of pattern and replacement */
714 	pattern.s[pattern.len] = (char)0;
715 	replacement.s[replacement.len] = (char)0;
716 	if (reg_replace(pattern.s, replacement.s, domain->s,
717 			&result) < 0) {
718 		pattern.s[pattern.len] = '!';
719 		replacement.s[replacement.len] = '!';
720 		LM_ERR("regexp replace failed\n");
721 		continue;
722 	}
723 	LM_INFO("resulted in replacement: '%.*s'\n", result.len, ZSW(result.s));
724 	pattern.s[pattern.len] = '!';
725 	replacement.s[replacement.len] = '!';
726 
727 	ret = check_rule(&result,naptr->services,naptr->services_len, &stack);
728 
729 	if (ret == 1) {
730 	    LM_INFO("positive return\n");
731 	} else if (ret == 0) {
732 	    LM_INFO("check_rule failed.\n");
733 	    stack_reset(&stack);
734 	    /* If we're in a recursive call, set the domain-replacement */
735 	    if ( rec_level > 0 ) {
736 		stack_push(&stack, domain_replacement_name.s.s, (char *) domain->s);
737 		stack.succeeded = 0;
738 	    }
739 	    failed = 1;
740 	} else {
741 	    return(DP_DDDS_RET_DNSERROR);
742     	}
743     }
744 
745     if (stack_succeeded(&stack)) {
746         LM_INFO("calling stack_to_avp.\n");
747 		stack_to_avp(&stack);
748 		return(DP_DDDS_RET_POSITIVE);
749     }
750 
751     LM_INFO("returning %d.\n",
752 	    (found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND));
753     return(  found_anything ? DP_DDDS_RET_NEGATIVE : DP_DDDS_RET_NOTFOUND );
754 }
755 
756 
757 /*!
758  * \brief Check if host in Request URI has DP-DDDS NAPTRs and if we can connect to them
759  * \param _msg SIP message
760  * \param _s1 unused
761  * \param _s2 unused
762  * \return negative on failure, positive on success
763  */
dp_can_connect(struct sip_msg * _msg,char * _s1,char * _s2)764 int dp_can_connect(struct sip_msg* _msg, char* _s1, char* _s2) {
765 
766 	static char domainname[MAX_DOMAIN_SIZE];
767 	str domain;
768 	int ret;
769 
770 	if (!is_route_type(REQUEST_ROUTE)) {
771 		LM_ERR("unsupported route type\n");
772 		return -1;
773 	}
774 
775 	if (parse_sip_msg_uri(_msg) < 0) {
776 		LM_ERR("failed to parse R-URI\n");
777 		return -1;
778 	}
779 
780 	if (_msg->parsed_uri.host.len >= MAX_DOMAIN_SIZE) {
781 		LM_ERR("domain buffer to small\n");
782 		return -1;
783 	}
784 
785 	/* copy domain into static buffer as later we sometimes need \0
786 	 * terminated strings
787 	 */
788 	domain.s = (char *) &(domainname[0]);
789 	domain.len = _msg->parsed_uri.host.len;
790 	memcpy(domain.s, _msg->parsed_uri.host.s, domain.len);
791 	domainname[domain.len] = '\0';
792 
793 	LM_DBG("domain is %.*s.\n", domain.len, ZSW(domain.s));
794 
795 	ret = dp_can_connect_str(&domain,0);
796 	LM_DBG("returning %d.\n", ret);
797 	return(ret);
798 }
799 
800 
801 /*!
802  * \brief Apply DP-DDDS policy to current SIP message
803  *
804  * Apply DP-DDDS policy to current SIP message. This means
805  * build a new destination URI from the policy AVP and export it
806  * as AVP. Then in kamailio.cfg this new target AVP can be pushed
807  * into the destination URI $duri
808  * \param _msg SIP message
809  * \param _s1 unused
810  * \param _s2 unused
811  * \return negative on failure, positive on succes
812  */
dp_apply_policy(struct sip_msg * _msg,char * _s1,char * _s2)813 int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) {
814 
815 	str *domain;
816 	int_str val;
817 	struct usr_avp *avp;
818 
819 	char duri[MAX_URI_SIZE];
820 	str duri_str;
821 	int len, didsomething;
822 	char *at; /* pointer to current location inside duri */
823 
824 	str host;
825 	int port, proto;
826 	struct socket_info* si;
827 
828 	if (!is_route_type(REQUEST_ROUTE)) {
829 		LM_ERR("unsupported route type\n");
830 		return -1;
831 	}
832 
833 	/*
834 	 * set the send_socket
835 	 */
836 
837 	/* search for send_socket AVP */
838 	avp = search_first_avp(send_socket_avp_name_str, send_socket_name, &val, 0);
839 	if (avp) {
840 		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
841 			LM_ERR("empty or non-string send_socket_avp, "
842 					"return with error ...\n");
843 			return -1;
844 		}
845 		LM_DBG("send_socket_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
846 		/* parse phostport - AVP str val is asciiz */
847 		/* FIXME: This code relies on the fact that the string value of an AVP
848 		 * is zero terminated, which may or may not be true in the future */
849 		if (parse_phostport(val.s.s, &(host.s), &(host.len), &port, &proto)) {
850 			LM_ERR("could not parse send_socket, return with error ...\n");
851 			return -1;
852 		}
853 		si = grep_sock_info( &host, (unsigned short) port, (unsigned short) proto);
854 		if (si) {
855 			set_force_socket(_msg, si);
856 		} else {
857 			LM_WARN("could not find socket for"
858 					"send_socket '%.*s'\n", val.s.len, ZSW(val.s.s));
859 		}
860 	} else {
861 		LM_DBG("send_socket_avp not found\n");
862 	}
863 
864 	/*
865 	 * set the destination URI
866 	 */
867 
868 	didsomething = 0; /* if no AVP is set, there is no need to set the DURI in the end */
869 
870 	if (parse_sip_msg_uri(_msg) < 0) {
871 		LM_ERR("failed to parse R-URI\n");
872 		return -1;
873 	}
874 
875 	at = (char *)&(duri[0]);
876 	len = 0;
877 	if ( (len + 4) >  MAX_URI_SIZE) {
878 		LM_ERR("duri buffer to small to add uri schema\n");
879 		return -1;
880 	}
881 	memcpy(at, "sip:", 4); at = at + 4; len = len + 4;
882 
883 	domain = &(_msg->parsed_uri.host);
884 	LM_DBG("domain is %.*s.\n", domain->len, ZSW(domain->s));
885 
886 	/* search for prefix and add it to duri buffer */
887 	avp = search_first_avp(domain_prefix_avp_name_str, domain_prefix_name, &val, 0);
888 	if (avp) {
889 		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
890 			LM_ERR("empty or non-string domain_prefix_avp, return with error ...\n");
891 			return -1;
892 		}
893 		LM_DBG("domain_prefix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
894 		if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
895 			LM_ERR("duri buffer to small to add domain prefix\n");
896 			return -1;
897 		}
898 		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
899 		*at = '.'; at = at + 1;	/* add . as delimiter between prefix and domain */
900 		didsomething = 1;
901 	} else {
902 		LM_DBG("domain_prefix_avp not found\n");
903 	}
904 
905 
906 	/* add domain to duri buffer */
907 	avp = search_first_avp(domain_replacement_avp_name_str, domain_replacement_name, &val, 0);
908 	if (avp) {
909 		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
910 			LM_ERR("empty or non-string domain_replacement_avp, return with"
911 					"error ...\n");
912 			return -1;
913 		}
914 		LM_DBG("domain_replacement_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
915 		if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
916 			LM_ERR("duri buffer to small to add domain replacement\n");
917 			return -1;
918 		}
919 		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
920 		didsomething = 1;
921 	} else {
922 	    LM_DBG("domain_replacement_avp not found, using original domain '"
923 				"%.*s'\n",domain->len, domain->s);
924 	    if ( (len + domain->len) >  MAX_URI_SIZE) {
925 		LM_ERR("duri buffer to small to add domain\n");
926 		return -1;
927 	    }
928 	    memcpy(at, domain->s, domain->len); at = at + domain->len;
929 	}
930 
931 	/* search for suffix and add it to duri buffer */
932 	avp = search_first_avp(domain_suffix_avp_name_str, domain_suffix_name, &val, 0);
933 	if (avp) {
934 		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
935 			LM_ERR("empty or non-string domain_suffix_avp,return with error .."
936 					"\n");
937 			return -1;
938 		}
939 		LM_DBG("domain_suffix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
940 		if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
941 			LM_ERR("duri buffer to small to add domain suffix\n");
942 			return -1;
943 		}
944 		*at = '.'; at = at + 1;	/* add . as delimiter between domain and suffix */
945 		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
946 		didsomething = 1;
947 	} else {
948 		LM_DBG("domain_suffix_avp not found\n");
949 	}
950 
951 	/* search for port override and add it to duri buffer */
952 	avp = search_first_avp(port_override_avp_name_str, port_override_name, &val, 0);
953 	if (avp) {
954 		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
955 			LM_ERR("empty or non-string port_override_avp, return with error ...\n");
956 			return -1;
957 		}
958 		LM_DBG("port_override_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
959 		/* We do not check if the port is valid */
960 		if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
961 			LM_ERR("duri buffer to small to add domain suffix\n");
962 			return -1;
963 		}
964 		*at = ':'; at = at + 1;	/* add : as delimiter between domain and port */
965 		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
966 		didsomething = 1;
967 	} else {
968 		LM_DBG("port_override_avp not found, using original port\n");
969 		if (_msg->parsed_uri.port.len) {
970 			LM_DBG("port found in RURI, reusing it for DURI\n");
971 			if ( (len + _msg->parsed_uri.port.len + 1) >  MAX_URI_SIZE) {
972 				LM_ERR("duri buffer to small to copy port\n");
973 				return -1;
974 			}
975 			*at = ':'; at = at + 1;
976 			/* add : as delimiter between domain and port */
977 			memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len);
978 			at = at + _msg->parsed_uri.port.len;
979 		} else {
980 			LM_DBG("port not found in RURI, no need to copy it to DURI\n");
981 		}
982 	}
983 
984 	/* search for transport override and add it to duri buffer */
985 	avp = search_first_avp(transport_override_avp_name_str, transport_override_name, &val, 0);
986 	if (avp) {
987 		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
988 			LM_ERR("empty or non-string transport_override_avp, "
989 					"return with error ...\n");
990 			return -1;
991 		}
992 		LM_DBG("transport_override_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
993 
994 		if ( (len + val.s.len + 11) >  MAX_URI_SIZE) {
995 			LM_ERR("duri buffer to small to add transport override\n");
996 			return -1;
997 		}
998 		/* add : as transport parameter to duri; NOTE: no checks if transport parameter is valid  */
999 		memcpy(at, ";transport=", 11); at = at + 11;
1000 		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
1001 		didsomething = 1;
1002 	} else {
1003 		LM_DBG("transport_override_avp not found, using original transport\n");
1004 		if (_msg->parsed_uri.transport.len) {
1005 			LM_DBG("transport found in RURI, reusing it for DURI\n");
1006 			if ( (len + _msg->parsed_uri.transport.len + 1) >  MAX_URI_SIZE) {
1007 				LM_ERR("duri buffer to small to copy transport\n");
1008 				return -1;
1009 			}
1010 			*at = ';'; at = at + 1; /* add : as delimiter between domain and port */
1011 			memcpy(at, _msg->parsed_uri.transport.s, _msg->parsed_uri.transport.len); at = at + _msg->parsed_uri.transport.len;
1012 		} else {
1013 			LM_DBG("transport not found in RURI, no need to copy it to DURI\n");
1014 		}
1015 	}
1016 
1017 	/* write new target DURI into DURI */
1018 	if (didsomething == 0) {
1019 		LM_DBG("no domainpolicy AVP set, no need to push new DURI\n");
1020 		return 2;
1021 	}
1022 	duri_str.s = (char *)&(duri[0]);
1023 	duri_str.len = at - duri_str.s;
1024 	LM_DBG("new DURI is '%.*s'\n",duri_str.len, ZSW(duri_str.s));
1025 	if(set_dst_uri(_msg, &duri_str)<0) {
1026 		LM_ERR("failed to se dst uri\n");
1027 		return -1;
1028 	}
1029 	/* dst_uri changes, so it makes sense to re-use the current uri for
1030 		forking */
1031 	ruri_mark_new(); /* re-use uri for serial forking */
1032 
1033 	return 1;
1034 }
1035 
1036