Skip to content

Commit 05e3ced

Browse files
kaberdavem330
authored andcommitted
[NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper
Introduce a helper function to parse a SIP-URI in a header value, optionally iterating through all headers of this kind. Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ea45f12 commit 05e3ced

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

include/linux/netfilter/nf_conntrack_sip.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
6767
unsigned int dataoff, unsigned int datalen,
6868
enum sip_header_types type,
6969
unsigned int *matchoff, unsigned int *matchlen);
70+
extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
71+
unsigned int *dataoff, unsigned int datalen,
72+
enum sip_header_types type, int *in_header,
73+
unsigned int *matchoff, unsigned int *matchlen,
74+
union nf_inet_addr *addr, __be16 *port);
7075

7176
extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
7277
unsigned int dataoff, unsigned int datalen,

net/netfilter/nf_conntrack_sip.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
194197
static 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
}
323326
EXPORT_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

Comments
 (0)