diff options
| author | Patrick McHardy <kaber@trash.net> | 2008-03-25 23:19:13 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-03-25 23:19:13 -0400 |
| commit | 05e3ced297fe755093140e7487e292fb7603316e (patch) | |
| tree | 2fab3c9f3572e7e0e103bece3d215cf1ad217461 | |
| parent | ea45f12a2766dae54e5426a23e8f4bafdbe2782e (diff) | |
[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 <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -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. |
