1 /*
2  * pv_headers
3  *
4  * Copyright (C)
5  * 2020 Victor Seva <vseva@sipwise.com>
6  * 2018 Kirill Solomko <ksolomko@sipwise.com>
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  */
25 
26 #include "../../core/strutils.h"
27 
28 #include "pv_headers.h"
29 #include "pvh_func.h"
30 #include "pvh_xavp.h"
31 #include "pvh_str.h"
32 #include "pvh_hash.h"
33 #include "pvh_hdr.h"
34 
35 static str xavi_helper_name = str_init("xavi_name");
36 
pvh_parse_msg(sip_msg_t * msg)37 int pvh_parse_msg(sip_msg_t *msg)
38 {
39 	if(msg->first_line.type == SIP_REQUEST) {
40 		if(!IS_SIP(msg)) {
41 			LM_DBG("non SIP request message\n");
42 			return 1;
43 		}
44 	} else if(msg->first_line.type == SIP_REPLY) {
45 		if(!IS_SIP_REPLY(msg)) {
46 			LM_DBG("non SIP reply message\n");
47 			return 1;
48 		}
49 	} else {
50 		LM_DBG("non SIP message\n");
51 		return 1;
52 	}
53 
54 	return 0;
55 }
56 
pvh_collect_headers(struct sip_msg * msg)57 int pvh_collect_headers(struct sip_msg *msg)
58 {
59 	struct hdr_field *hf = NULL;
60 	str name = STR_NULL;
61 	str val = STR_NULL;
62 	char hvals[header_name_size][header_value_size];
63 	int idx = 0, d_size = 0;
64 	str val_part = STR_NULL;
65 	char *marker = NULL;
66 
67 	if(pvh_hdrs_collected(msg)) {
68 		LM_ERR("headers are already collected\n");
69 		return -1;
70 	}
71 
72 	if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
73 		LM_ERR("error parsing headers\n");
74 		return -1;
75 	}
76 
77 	for(hf = msg->headers; hf; hf = hf->next) {
78 		LM_DBG("collect header[%.*s]: %.*s\n", hf->name.len, hf->name.s,
79 				hf->body.len, hf->body.s);
80 
81 		switch(hf->type) {
82 			case HDR_FROM_T:
83 				name.len = _hdr_from.len;
84 				name.s = _hdr_from.s;
85 				LM_DBG("force [From] as key\n");
86 				break;
87 			case HDR_TO_T:
88 				name.len = _hdr_to.len;
89 				name.s = _hdr_to.s;
90 				LM_DBG("force [To] as key\n");
91 				break;
92 			default:
93 				name.len = hf->name.len;
94 				name.s = hf->name.s;
95 		}
96 		val.len = hf->body.len;
97 		val.s = hf->body.s;
98 
99 		if(( marker = pvh_detect_split_char(val.s)) != NULL
100 				&& str_hash_case_get(&split_headers, name.s, name.len)) {
101 
102 			if(pvh_split_values(&val, hvals, &d_size, 1, marker) < 0) {
103 				LM_ERR("could not parse %.*s header comma separated "
104 					   "value",
105 						name.len, name.s);
106 				return -1;
107 			}
108 
109 			for(idx = 0; idx < d_size; idx++) {
110 				val_part.s = hvals[idx];
111 				val_part.len = strlen(hvals[idx]);
112 				if(pvh_set_xavi(msg, &xavi_name, &name, &val_part, SR_XTYPE_STR,
113 						   0, 1)
114 						< 0)
115 					return -1;
116 			}
117 			continue;
118 		}
119 		if(pvh_set_xavi(msg, &xavi_name, &name, &val, SR_XTYPE_STR, 0, 1) < 0)
120 			return -1;
121 	}
122 
123 	if(pvh_set_xavi(msg, &xavi_helper_xname, &xavi_helper_name, &xavi_name,
124 			   SR_XTYPE_STR, 0, 0)
125 			< 0)
126 		return -1;
127 
128 	pvh_hdrs_set_collected(msg);
129 
130 	return 1;
131 }
132 
pvh_apply_headers(struct sip_msg * msg)133 int pvh_apply_headers(struct sip_msg *msg)
134 {
135 	sr_xavp_t *xavi = NULL;
136 	sr_xavp_t *sub = NULL;
137 	struct str_hash_table rm_hdrs;
138 	int from_cnt = 0, to_cnt = 0;
139 	char t[header_name_size];
140 	char tv[2][header_value_size];
141 	str display = {tv[0], header_value_size};
142 	str uri = {tv[1], header_value_size};
143 	str br_xname = {t, header_name_size};
144 	int skip_from_to = 0, keys_count = 0;
145 	int res = -1;
146 
147 	memset(&rm_hdrs, 0, sizeof(struct str_hash_table));
148 
149 	if(pvh_hdrs_applied(msg)) {
150 		LM_ERR("headers are already applied\n");
151 		return -1;
152 	}
153 
154 	if(parse_headers(msg, HDR_EOH_F, 0) < 0) {
155 		LM_ERR("error parsing headers\n");
156 		return -1;
157 	}
158 
159 	pvh_get_branch_xname(msg, &xavi_name, &br_xname);
160 
161 	if((xavi = xavi_get(&br_xname, NULL)) == NULL
162 			&& (xavi = xavi_get(&xavi_name, NULL)) == NULL) {
163 		LM_ERR("missing xavi %.*s, run pv_collect_headers() first\n",
164 				xavi_name.len, xavi_name.s);
165 		return -1;
166 	}
167 	if(xavi->val.type != SR_XTYPE_XAVP) {
168 		LM_ERR("not xavp child type %.*s\n", xavi_name.len, xavi_name.s);
169 		return -1;
170 	}
171 
172 	if((sub = xavi->val.v.xavp) == NULL) {
173 		LM_ERR("invalid xavp structure: %.*s\n", xavi_name.len, xavi_name.s);
174 		return -1;
175 	}
176 	keys_count = pvh_xavi_keys_count(&sub);
177 	if(str_hash_alloc(&rm_hdrs, keys_count) < 0) {
178 		PKG_MEM_ERROR;
179 		return -1;
180 	}
181 	LM_DBG("xavi->name:%.*s br_xname:%.*s keys_count: %d\n", xavi->name.len,
182 			xavi->name.s, br_xname.len, br_xname.s, keys_count);
183 	str_hash_init(&rm_hdrs);
184 
185 	if(msg->first_line.type == SIP_REPLY
186 			|| msg->first_line.u.request.method_value == METHOD_ACK
187 			|| msg->first_line.u.request.method_value == METHOD_PRACK
188 			|| msg->first_line.u.request.method_value == METHOD_BYE) {
189 		skip_from_to = 1;
190 		if(msg->to == NULL) {
191 			LM_DBG("no To header, can't store To info in parsed\n");
192 		} else {
193 			if(pvh_set_parsed(msg, &_hdr_to, &msg->to->body, NULL) == NULL)
194 				LM_ERR("can't store To info in parsed\n");
195 		}
196 	}
197 
198 	do {
199 		if(pvh_skip_header(&sub->name))
200 			continue;
201 
202 		if(cmpi_str(&sub->name, &_hdr_from) == 0) {
203 			if(skip_from_to) {
204 				LM_DBG("skip From header change in reply messages\n");
205 				continue;
206 			}
207 			if(cmp_str(&sub->val.v.s, &msg->from->body) == 0) {
208 				LM_DBG("skip unchanged From header\n");
209 				continue;
210 			}
211 			if(from_cnt > 0)
212 				continue;
213 
214 			memset(display.s, 0, header_value_size);
215 			memset(uri.s, 0, header_value_size);
216 
217 			if(pvh_extract_display_uri(sub->val.v.s.s, &display, &uri) < 0) {
218 				LM_ERR("error parsing From header\n");
219 				goto err;
220 			}
221 
222 			if(uac.replace_from != NULL) {
223 				LM_DBG("replace_from[%s]: %s %s\n", sub->name.s, display.s,
224 						uri.s);
225 				if(display.len == 0)
226 					pvh_real_hdr_remove_display(msg, &sub->name);
227 				uac.replace_from(msg, &display, &uri);
228 			}
229 
230 			from_cnt++;
231 			continue;
232 		}
233 
234 		if(cmpi_str(&sub->name, &_hdr_to) == 0) {
235 			if(skip_from_to) {
236 				LM_DBG("skip To header change in reply messages\n");
237 				continue;
238 			}
239 			if(cmp_str(&sub->val.v.s, &msg->to->body) == 0) {
240 				LM_DBG("skip unchanged To header\n");
241 				continue;
242 			}
243 			if(to_cnt > 0)
244 				continue;
245 
246 			memset(display.s, 0, header_value_size);
247 			memset(uri.s, 0, header_value_size);
248 
249 			if(pvh_extract_display_uri(sub->val.v.s.s, &display, &uri) < 0) {
250 				LM_ERR("error parsing To header\n");
251 				goto err;
252 			}
253 
254 			if(uac.replace_to != NULL) {
255 				LM_DBG("replace_to[%s]: %s %s\n", sub->name.s, display.s,
256 						uri.s);
257 				if(display.len == 0)
258 					pvh_real_hdr_remove_display(msg, &sub->name);
259 				uac.replace_to(msg, &display, &uri);
260 			}
261 
262 			to_cnt++;
263 			continue;
264 		}
265 
266 		if(cmpi_str(&sub->name, &_hdr_reply_reason) == 0) {
267 			if(str_hash_case_get(&rm_hdrs, sub->name.s, sub->name.len))
268 				continue;
269 			pvh_real_replace_reply_reason(msg, &sub->val.v.s);
270 			pvh_str_hash_add_key(&rm_hdrs, &sub->name);
271 			continue;
272 		}
273 
274 		if(!str_hash_case_get(&rm_hdrs, sub->name.s, sub->name.len)) {
275 			if(!pvh_avp_is_null(sub) && xavi_count(&sub->name, &sub) == 1) {
276 				LM_DBG("replace header[%s]: %s\n", sub->name.s, sub->val.v.s.s);
277 				pvh_real_hdr_replace(msg, &sub->name, &sub->val.v.s);
278 				pvh_str_hash_add_key(&rm_hdrs, &sub->name);
279 				continue;
280 			}
281 			LM_DBG("remove header[%s]: %s\n", sub->name.s, sub->val.v.s.s);
282 			pvh_real_hdr_del_by_name(msg, &sub->name);
283 			pvh_str_hash_add_key(&rm_hdrs, &sub->name);
284 		}
285 
286 		if(!pvh_avp_is_null(sub) && !pvh_single_header(&sub->name)) {
287 			pvh_real_hdr_append(msg, &sub->name, &sub->val.v.s);
288 			LM_DBG("append header[%s]: %s\n", sub->name.s, sub->val.v.s.s);
289 		}
290 	} while((sub = sub->next) != NULL);
291 
292 	pvh_hdrs_set_applied(msg);
293 
294 	res = 1;
295 
296 err:
297 	if(rm_hdrs.size)
298 		pvh_str_hash_free(&rm_hdrs);
299 	return res;
300 }
301 
pvh_reset_headers(struct sip_msg * msg)302 int pvh_reset_headers(struct sip_msg *msg)
303 {
304 	char t[header_name_size];
305 	str br_xname = {t, header_name_size};
306 
307 	pvh_get_branch_xname(msg, &xavi_name, &br_xname);
308 	LM_DBG("clean xavi:%.*s\n", br_xname.len, br_xname.s);
309 	xavi_rm_by_name(&br_xname, 1, NULL);
310 	pvh_get_branch_xname(msg, &xavi_parsed_xname, &br_xname);
311 	LM_DBG("clean xavi:%.*s\n", br_xname.len, br_xname.s);
312 	xavi_rm_by_name(&br_xname, 1, NULL);
313 
314 	pvh_hdrs_reset_flags(msg);
315 
316 	return 1;
317 }
318 
pvh_check_header(struct sip_msg * msg,str * hname)319 int pvh_check_header(struct sip_msg *msg, str *hname)
320 {
321 
322 	if(pvh_xavi_get_child(msg, &xavi_name, hname) == NULL)
323 		return -1;
324 
325 	return 1;
326 }
327 
pvh_append_header(struct sip_msg * msg,str * hname,str * hvalue)328 int pvh_append_header(struct sip_msg *msg, str *hname, str *hvalue)
329 {
330 	return pvh_set_xavi(msg, &xavi_name, hname, hvalue, SR_XTYPE_STR, 0, 1);
331 }
332 
pvh_modify_header(struct sip_msg * msg,str * hname,str * hvalue,int indx)333 int pvh_modify_header(struct sip_msg *msg, str *hname, str *hvalue, int indx)
334 {
335 	return pvh_set_xavi(msg, &xavi_name, hname, hvalue, SR_XTYPE_STR, indx, 0);
336 }
337 
pvh_remove_header(struct sip_msg * msg,str * hname,int indx)338 int pvh_remove_header(struct sip_msg *msg, str *hname, int indx)
339 {
340 	sr_xavp_t *avp = NULL;
341 	int count = 0;
342 
343 	if((avp = pvh_xavi_get_child(msg, &xavi_name, hname)) == NULL)
344 		return 1;
345 
346 	if(indx < 0) {
347 		count = xavi_count(hname, &avp);
348 		do {
349 			if(pvh_set_xavi(
350 					   msg, &xavi_name, hname, NULL, SR_XTYPE_STR, indx++, 0)
351 					< 1)
352 				return -1;
353 		} while(indx < count);
354 	} else {
355 		if(pvh_set_xavi(msg, &xavi_name, hname, NULL, SR_XTYPE_STR, indx, 0)
356 				< 1)
357 			return -1;
358 	}
359 
360 	return 1;
361 }
362