diff options
-rw-r--r-- | include/linux/netfilter/nf_conntrack_sip.h | 5 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 107 |
2 files changed, 112 insertions, 0 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index ccc701422963..87bc6f79efc4 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h | |||
@@ -67,6 +67,11 @@ extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, | |||
67 | unsigned int dataoff, unsigned int datalen, | 67 | unsigned int dataoff, unsigned int datalen, |
68 | enum sip_header_types type, | 68 | enum sip_header_types type, |
69 | unsigned int *matchoff, unsigned int *matchlen); | 69 | 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); | ||
70 | 75 | ||
71 | extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, | 76 | extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, |
72 | unsigned int dataoff, unsigned int datalen, | 77 | unsigned int dataoff, unsigned int datalen, |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index cbc91598acee..a74d76a97312 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -190,6 +190,9 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request); | |||
190 | * whitespace and the values. Whitespace in this context means any amount of | 190 | * whitespace and the values. Whitespace in this context means any amount of |
191 | * tabs, spaces and continuation lines, which are treated as a single whitespace | 191 | * tabs, spaces and continuation lines, which are treated as a single whitespace |
192 | * character. | 192 | * character. |
193 | * | ||
194 | * Some headers may appear multiple times. A comma seperated list of values is | ||
195 | * equivalent to multiple headers. | ||
193 | */ | 196 | */ |
194 | static const struct sip_header ct_sip_hdrs[] = { | 197 | static const struct sip_header ct_sip_hdrs[] = { |
195 | [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), | 198 | [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, | |||
322 | } | 325 | } |
323 | EXPORT_SYMBOL_GPL(ct_sip_get_header); | 326 | EXPORT_SYMBOL_GPL(ct_sip_get_header); |
324 | 327 | ||
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 | |||
325 | /* SDP header parsing: a SDP session description contains an ordered set of | 432 | /* SDP header parsing: a SDP session description contains an ordered set of |
326 | * headers, starting with a section containing general session parameters, | 433 | * headers, starting with a section containing general session parameters, |
327 | * optionally followed by multiple media descriptions. | 434 | * optionally followed by multiple media descriptions. |