@@ -190,6 +190,9 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request);
190190 * whitespace and the values. Whitespace in this context means any amount of
191191 * tabs, spaces and continuation lines, which are treated as a single whitespace
192192 * character.
193+ *
194+ * Some headers may appear multiple times. A comma seperated list of values is
195+ * equivalent to multiple headers.
193196 */
194197static const struct sip_header ct_sip_hdrs [] = {
195198 [SIP_HDR_FROM ] = SIP_HDR ("From" , "f" , "sip:" , skp_epaddr_len ),
@@ -322,6 +325,110 @@ int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
322325}
323326EXPORT_SYMBOL_GPL (ct_sip_get_header );
324327
328+ /* Get next header field in a list of comma seperated values */
329+ static int ct_sip_next_header (const struct nf_conn * ct , const char * dptr ,
330+ unsigned int dataoff , unsigned int datalen ,
331+ enum sip_header_types type ,
332+ unsigned int * matchoff , unsigned int * matchlen )
333+ {
334+ const struct sip_header * hdr = & ct_sip_hdrs [type ];
335+ const char * start = dptr , * limit = dptr + datalen ;
336+ int shift = 0 ;
337+
338+ dptr += dataoff ;
339+
340+ dptr = ct_sip_header_search (dptr , limit , "," , strlen ("," ));
341+ if (!dptr )
342+ return 0 ;
343+
344+ dptr = ct_sip_header_search (dptr , limit , hdr -> search , hdr -> slen );
345+ if (!dptr )
346+ return 0 ;
347+ dptr += hdr -> slen ;
348+
349+ * matchoff = dptr - start ;
350+ * matchlen = hdr -> match_len (ct , dptr , limit , & shift );
351+ if (!* matchlen )
352+ return -1 ;
353+ * matchoff += shift ;
354+ return 1 ;
355+ }
356+
357+ /* Walk through headers until a parsable one is found or no header of the
358+ * given type is left. */
359+ static int ct_sip_walk_headers (const struct nf_conn * ct , const char * dptr ,
360+ unsigned int dataoff , unsigned int datalen ,
361+ enum sip_header_types type , int * in_header ,
362+ unsigned int * matchoff , unsigned int * matchlen )
363+ {
364+ int ret ;
365+
366+ if (in_header && * in_header ) {
367+ while (1 ) {
368+ ret = ct_sip_next_header (ct , dptr , dataoff , datalen ,
369+ type , matchoff , matchlen );
370+ if (ret > 0 )
371+ return ret ;
372+ if (ret == 0 )
373+ break ;
374+ dataoff += * matchoff ;
375+ }
376+ * in_header = 0 ;
377+ }
378+
379+ while (1 ) {
380+ ret = ct_sip_get_header (ct , dptr , dataoff , datalen ,
381+ type , matchoff , matchlen );
382+ if (ret > 0 )
383+ break ;
384+ if (ret == 0 )
385+ return ret ;
386+ dataoff += * matchoff ;
387+ }
388+
389+ if (in_header )
390+ * in_header = 1 ;
391+ return 1 ;
392+ }
393+
394+ /* Locate a SIP header, parse the URI and return the offset and length of
395+ * the address as well as the address and port themselves. A stream of
396+ * headers can be parsed by handing in a non-NULL datalen and in_header
397+ * pointer.
398+ */
399+ int ct_sip_parse_header_uri (const struct nf_conn * ct , const char * dptr ,
400+ unsigned int * dataoff , unsigned int datalen ,
401+ enum sip_header_types type , int * in_header ,
402+ unsigned int * matchoff , unsigned int * matchlen ,
403+ union nf_inet_addr * addr , __be16 * port )
404+ {
405+ const char * c , * limit = dptr + datalen ;
406+ unsigned int p ;
407+ int ret ;
408+
409+ ret = ct_sip_walk_headers (ct , dptr , dataoff ? * dataoff : 0 , datalen ,
410+ type , in_header , matchoff , matchlen );
411+ WARN_ON (ret < 0 );
412+ if (ret == 0 )
413+ return ret ;
414+
415+ if (!parse_addr (ct , dptr + * matchoff , & c , addr , limit ))
416+ return -1 ;
417+ if (* c == ':' ) {
418+ c ++ ;
419+ p = simple_strtoul (c , (char * * )& c , 10 );
420+ if (p < 1024 || p > 65535 )
421+ return -1 ;
422+ * port = htons (p );
423+ } else
424+ * port = htons (SIP_PORT );
425+
426+ if (dataoff )
427+ * dataoff = c - dptr ;
428+ return 1 ;
429+ }
430+ EXPORT_SYMBOL_GPL (ct_sip_parse_header_uri );
431+
325432/* SDP header parsing: a SDP session description contains an ordered set of
326433 * headers, starting with a section containing general session parameters,
327434 * optionally followed by multiple media descriptions.
0 commit comments