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