/src/opensips/parser/parse_hname2.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Fast 32-bit Header Field Name Parser |
3 | | * |
4 | | * Copyright (C) 2001-2003 FhG Fokus |
5 | | * |
6 | | * This file is part of opensips, a free SIP server. |
7 | | * |
8 | | * opensips 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 | | * opensips 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 | | * 2003-02-28 scratchpad compatibility abandoned (jiri) |
25 | | * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri) |
26 | | * 2003-05-01 added support for Accept HF (janakj) |
27 | | * 2006-02-17 Session-Expires, Min-SE (dhsueh@somanetworks.com) |
28 | | */ |
29 | | |
30 | | |
31 | | #include "parse_hname2.h" |
32 | | #include "keys.h" |
33 | | #include "../ut.h" /* q_memchr */ |
34 | | |
35 | 839k | #define LOWER_BYTE(b) ((b) | 0x20U) |
36 | 2.10M | #define LOWER_DWORD(d) ((d) | 0x20202020U) |
37 | | |
38 | | /* |
39 | | * Skip all white-chars and return position of the first |
40 | | * non-white char |
41 | | */ |
42 | | static inline char* skip_ws(char* p, char *end) |
43 | 62.9k | { |
44 | 83.2k | for(; p < end; p++) { |
45 | 83.0k | if ((*p != ' ') && (*p != '\t')) return p; |
46 | 83.0k | } |
47 | 265 | return p; |
48 | 62.9k | } |
49 | | |
50 | | /* |
51 | | * Parser macros |
52 | | */ |
53 | | #include "case_via.h" /* Via */ |
54 | | #include "case_from.h" /* From */ |
55 | | #include "case_to.h" /* To */ |
56 | | #include "case_cseq.h" /* CSeq */ |
57 | | #include "case_call.h" /* Call-ID */ |
58 | | #include "case_cont.h" /* Contact, Content-Type, Content-Length, |
59 | | Content-Purpose, Content-Action, |
60 | | Content-Disposition */ |
61 | | #include "case_rout.h" /* Route */ |
62 | | #include "case_max.h" /* Max-Forwards */ |
63 | | #include "case_reco.h" /* Record-Route */ |
64 | | #include "case_path.h" /* Path */ |
65 | | #include "case_auth.h" /* Authorization */ |
66 | | #include "case_expi.h" /* Expires */ |
67 | | #include "case_prox.h" /* Proxy-Authorization, Proxy-Require */ |
68 | | #include "case_allo.h" /* Allow */ |
69 | | #include "case_unsu.h" /* Unsupported */ |
70 | | #include "case_even.h" /* Event */ |
71 | | #include "case_acce.h" /* Accept, Accept-Language */ |
72 | | #include "case_orga.h" /* Organization */ |
73 | | #include "case_prio.h" /* Priority */ |
74 | | #include "case_subj.h" /* Subject */ |
75 | | #include "case_user.h" /* User-Agent */ |
76 | | #include "case_supp.h" /* Supported */ |
77 | | #include "case_dive.h" /* Diversion */ |
78 | | #include "case_remo.h" /* Remote-Party-ID */ |
79 | | #include "case_refe.h" /* Refer-To */ |
80 | | #include "case_sess.h" /* Session-Expires */ |
81 | | #include "case_min_.h" /* Min-SE */ |
82 | | #include "case_p_pr.h" /* P-Preferred-Identity */ |
83 | | #include "case_p_as.h" /* P-Asserted-Identity */ |
84 | | #include "case_priv.h" /* Privacy */ |
85 | | #include "case_retr.h" /* Retry-After */ |
86 | | #include "case_www.h" /* WWW-Authenticate */ |
87 | | #include "case_feat.h" /* Feature-Caps */ |
88 | | #include "case_repl.h" /* Replaces */ |
89 | | #include "case_to_p.h" /* To-Path */ |
90 | | #include "case_mess.h" /* Message-ID */ |
91 | | #include "case_byte.h" /* Byte-Range */ |
92 | | #include "case_fail.h" /* Failure-Report */ |
93 | | #include "case_succ.h" /* Success-Report */ |
94 | | #include "case_stat.h" /* Status */ |
95 | | #include "case_use_.h" /* Use-Path */ |
96 | | #include "case_secu.h" /* Security-Client, Security-Server, |
97 | | Security-Verify */ |
98 | | |
99 | | |
100 | | /* |
101 | | * Read 4-bytes from memory, as an unsigned integer |
102 | | * Reading byte by byte ensures that the code works also on HW which |
103 | | * does not allow reading 4-bytes at once from unaligned memory position |
104 | | * (Sparc for example) |
105 | | */ |
106 | | #define READ(addr) \ |
107 | 982k | ((unsigned)*((unsigned char *)addr + 0) + \ |
108 | 982k | ((unsigned)*((unsigned char *)addr + 1) << 8) + \ |
109 | 982k | ((unsigned)*((unsigned char *)addr + 2) << 16) + \ |
110 | 982k | ((unsigned)*((unsigned char *)addr + 3) << 24)) |
111 | | |
112 | | #ifdef FUZZ_BUILD |
113 | | /* fuzzers are sensible to heap read overflows, so enable all "HAVE" checks */ |
114 | 896k | #define HAVE(bytes) (end - p >= (long)(bytes)) |
115 | | #else |
116 | | /* with PKG memory, parser read overflows of a few bytes are harmless, since |
117 | | * the memory is pre-allocated and the read cannot SIGSEGV, making the parser |
118 | | * a lot more performant in production */ |
119 | | #define HAVE(bytes) 1 |
120 | | #endif |
121 | | |
122 | | #define FIRST_QUATERNIONS \ |
123 | 550 | case _via1_: via1_CASE; \ |
124 | 12.4k | case _from_: from_CASE; \ |
125 | 274 | case _to12_: to12_CASE; \ |
126 | 46.3k | case _cseq_: cseq_CASE; \ |
127 | 46.3k | case _call_: call_CASE; \ |
128 | 34.6k | case _cont_: cont_CASE; \ |
129 | 7.17k | case _rout_: rout_CASE; \ |
130 | 15.0k | case _max__: max_CASE; \ |
131 | 10.7k | case _reco_: reco_CASE; \ |
132 | 370 | case _via2_: via2_CASE; \ |
133 | 17.0k | case _auth_: auth_CASE; \ |
134 | 10.4k | case _supp_: supp_CASE; \ |
135 | 13.9k | case _expi_: expi_CASE; \ |
136 | 42.3k | case _prox_: prox_CASE; \ |
137 | 10.8k | case _allo_: allo_CASE; \ |
138 | 6.00k | case _path_: path_CASE; \ |
139 | 12.4k | case _unsu_: unsu_CASE; \ |
140 | 4.19k | case _even_: even_CASE; \ |
141 | 38.2k | case _acce_: acce_CASE; \ |
142 | 14.0k | case _orga_: orga_CASE; \ |
143 | 8.09k | case _prio_: prio_CASE; \ |
144 | 16.5k | case _subj_: subj_CASE; \ |
145 | 10.6k | case _user_: user_CASE; \ |
146 | 14.5k | case _dive_: dive_CASE; \ |
147 | 10.6k | case _remo_: remo_CASE; \ |
148 | 7.02k | case _refe_: refe_CASE; \ |
149 | 14.8k | case _sess_: sess_CASE; \ |
150 | 22.1k | case _min__: min__CASE; \ |
151 | 12.9k | case _p_pr_: p_pr_CASE; \ |
152 | 16.0k | case _p_as_: p_as_CASE; \ |
153 | 17.0k | case _priv_: priv_CASE; \ |
154 | 15.4k | case _retr_: retr_CASE; \ |
155 | 19.1k | case _www__: www_CASE; \ |
156 | 4.14k | case _feat_: feat_CASE; \ |
157 | 8.05k | case _repl_: repl_CASE; \ |
158 | 5.43k | case _to_p_: to_p_CASE; \ |
159 | 14.1k | case _mess_: mess_CASE; \ |
160 | 23.0k | case _byte_: byte_CASE; \ |
161 | 11.0k | case _fail_: fail_CASE; \ |
162 | 6.67k | case _succ_: succ_CASE; \ |
163 | 4.74k | case _stat_: stat_CASE; \ |
164 | 1.89k | case _use__: use__CASE; \ |
165 | 43.2k | case _secu_: secu_CASE; \ |
166 | | |
167 | | |
168 | | #define PARSE_COMPACT(id) \ |
169 | 205k | switch(*(p + 1)) { \ |
170 | 11.5k | case ' ': \ |
171 | 19.7k | case '\t': \ |
172 | 19.7k | hdr->type = id; \ |
173 | 19.7k | hdr->name.len = 1; \ |
174 | 19.7k | p += 2; \ |
175 | 19.7k | goto dc_end; \ |
176 | 107k | case ':': \ |
177 | 107k | hdr->type = id; \ |
178 | 107k | hdr->name.len = 1; \ |
179 | 107k | return (p + 2); \ |
180 | 205k | } |
181 | | |
182 | | |
183 | | char* parse_hname2(char* begin, char* end, struct hdr_field* hdr) |
184 | 1.14M | { |
185 | 1.14M | register char* p; |
186 | 1.14M | register unsigned int val; |
187 | | |
188 | 1.14M | if ((end - begin) < 4) { |
189 | 841 | hdr->type = HDR_ERROR_T; |
190 | 841 | return begin; |
191 | 841 | } |
192 | | |
193 | 1.14M | p = begin; |
194 | | |
195 | 1.14M | val = LOWER_DWORD(READ(p)); |
196 | 1.14M | hdr->name.s = begin; |
197 | | |
198 | 1.14M | switch(val) { |
199 | | |
200 | 1.13M | FIRST_QUATERNIONS; |
201 | | /* fall through */ |
202 | | |
203 | 1.13M | default: |
204 | 493k | switch(LOWER_BYTE(*p)) { |
205 | 59.8k | case 't': |
206 | 59.8k | switch(LOWER_BYTE(*(p + 1))) { |
207 | 1.86k | case 'o': |
208 | 1.86k | p += 2; |
209 | 1.86k | hdr->type = HDR_TO_T; |
210 | 1.86k | hdr->name.len = 2; |
211 | 1.86k | goto dc_cont; |
212 | 1.70k | case ' ': |
213 | 1.70k | case '\t': |
214 | 1.70k | p += 2; |
215 | 1.70k | hdr->type = HDR_TO_T; |
216 | 1.70k | hdr->name.len = 1; |
217 | 1.70k | goto dc_end; |
218 | 43.2k | case ':': |
219 | 43.2k | hdr->type = HDR_TO_T; |
220 | 43.2k | hdr->name.len = 1; |
221 | 43.2k | return (p + 2); |
222 | 59.8k | } |
223 | 12.9k | break; |
224 | 69.3k | case 'v': PARSE_COMPACT(HDR_VIA_T); break; |
225 | 12.7k | case 'f': PARSE_COMPACT(HDR_FROM_T); break; |
226 | 13.2k | case 'i': PARSE_COMPACT(HDR_CALLID_T); break; |
227 | 32.7k | case 'm': PARSE_COMPACT(HDR_CONTACT_T); break; |
228 | 7.14k | case 'l': PARSE_COMPACT(HDR_CONTENTLENGTH_T); break; |
229 | 2.55k | case 'k': PARSE_COMPACT(HDR_SUPPORTED_T); break; |
230 | 36.5k | case 'c': PARSE_COMPACT(HDR_CONTENTTYPE_T); break; |
231 | 16.3k | case 'o': PARSE_COMPACT(HDR_EVENT_T); break; |
232 | 15.1k | case 'x': PARSE_COMPACT(HDR_SESSION_EXPIRES_T); break; |
233 | 493k | } |
234 | 319k | goto other; |
235 | 1.14M | } |
236 | | /* the above swtich will never continue here */ |
237 | | |
238 | | |
239 | 32.5k | dc_end: |
240 | | /* HDR name entirely found, consume WS till colon */ |
241 | | /* overflow during the "switch-case" parsing ? */ |
242 | 32.5k | if (p>=end) |
243 | 20 | goto error; |
244 | 32.5k | p = skip_ws(p, end); |
245 | 32.5k | if (p >= end || *p != ':') |
246 | 136 | goto error; |
247 | | /* hdr type, name should be already set at this point */ |
248 | 32.4k | return (p+1); |
249 | | /*done*/ |
250 | | |
251 | | |
252 | 255k | dc_cont: |
253 | | /* HDR name partially found, see what's next */ |
254 | | /* overflow during the "switch-case" parsing ? */ |
255 | 255k | if (p>=end) |
256 | 159 | goto error; |
257 | | /* hdr type, name should be already set at this point (for partial finding) */ |
258 | 255k | switch (*p) { |
259 | 222k | case ':' : |
260 | 222k | return (p+1); |
261 | 767 | case ' ': |
262 | 6.14k | case '\t': |
263 | | /* consume spaces to the end of name */ |
264 | 6.14k | p = skip_ws( p+1, end); |
265 | 6.14k | if (p >= end || *p != ':') |
266 | 26 | goto error; |
267 | 6.12k | return (p+1); |
268 | | /* default: it seems the hdr name continues, fall to "other" */ |
269 | 255k | } |
270 | | |
271 | | |
272 | 668k | other: |
273 | | /* Unknown header type */ |
274 | 668k | hdr->type = HDR_OTHER_T; |
275 | | /* if overflow during the "switch-case" parsing, the "while" will |
276 | | * exit and we will fall in the "error" section */ |
277 | 7.32M | while ( p < end ) { |
278 | 7.32M | switch (*p) { |
279 | 639k | case ':' : |
280 | 639k | hdr->name.len = p - hdr->name.s; |
281 | 639k | return (p + 1); |
282 | 18.6k | case ' ' : |
283 | 24.2k | case '\t': |
284 | 24.2k | hdr->name.len = p - hdr->name.s; |
285 | 24.2k | p = skip_ws(p+1, end); |
286 | 24.2k | if (p >= end || *p != ':') |
287 | 972 | goto error; |
288 | 23.2k | return (p+1); |
289 | 7.32M | } |
290 | 6.65M | p++; |
291 | 6.65M | } |
292 | | |
293 | 5.13k | error: |
294 | | /* No colon found, error.. */ |
295 | 5.13k | hdr->type = HDR_ERROR_T; |
296 | 5.13k | hdr->name.s = 0; |
297 | 5.13k | hdr->name.len = 0; |
298 | 5.13k | return 0; |
299 | 668k | } |