diff options
| -rw-r--r-- | include/linux/netfilter/nf_conntrack_sip.h | 2 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 4 | ||||
| -rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 87 |
3 files changed, 73 insertions, 20 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 0dfc8b7210a3..89f2a627f3f0 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h | |||
| @@ -164,7 +164,7 @@ extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr | |||
| 164 | unsigned int dataoff, unsigned int datalen, | 164 | unsigned int dataoff, unsigned int datalen, |
| 165 | const char *name, | 165 | const char *name, |
| 166 | unsigned int *matchoff, unsigned int *matchlen, | 166 | unsigned int *matchoff, unsigned int *matchlen, |
| 167 | union nf_inet_addr *addr); | 167 | union nf_inet_addr *addr, bool delim); |
| 168 | extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, | 168 | extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, |
| 169 | unsigned int off, unsigned int datalen, | 169 | unsigned int off, unsigned int datalen, |
| 170 | const char *name, | 170 | const char *name, |
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index ea4a23813d26..eef8f29e8bf8 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
| @@ -173,7 +173,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, | |||
| 173 | * the reply. */ | 173 | * the reply. */ |
| 174 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, | 174 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
| 175 | "maddr=", &poff, &plen, | 175 | "maddr=", &poff, &plen, |
| 176 | &addr) > 0 && | 176 | &addr, true) > 0 && |
| 177 | addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && | 177 | addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && |
| 178 | addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { | 178 | addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { |
| 179 | buflen = sprintf(buffer, "%pI4", | 179 | buflen = sprintf(buffer, "%pI4", |
| @@ -187,7 +187,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, | |||
| 187 | * from which the server received the request. */ | 187 | * from which the server received the request. */ |
| 188 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, | 188 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
| 189 | "received=", &poff, &plen, | 189 | "received=", &poff, &plen, |
| 190 | &addr) > 0 && | 190 | &addr, false) > 0 && |
| 191 | addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && | 191 | addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && |
| 192 | addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { | 192 | addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { |
| 193 | buflen = sprintf(buffer, "%pI4", | 193 | buflen = sprintf(buffer, "%pI4", |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 2fb666920cc9..5c0a112aeee6 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
| @@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr, | |||
| 183 | return len + digits_len(ct, dptr, limit, shift); | 183 | return len + digits_len(ct, dptr, limit, shift); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | static int parse_addr(const struct nf_conn *ct, const char *cp, | 186 | static int sip_parse_addr(const struct nf_conn *ct, const char *cp, |
| 187 | const char **endp, union nf_inet_addr *addr, | 187 | const char **endp, union nf_inet_addr *addr, |
| 188 | const char *limit) | 188 | const char *limit, bool delim) |
| 189 | { | 189 | { |
| 190 | const char *end; | 190 | const char *end; |
| 191 | int ret = 0; | 191 | int ret; |
| 192 | 192 | ||
| 193 | if (!ct) | 193 | if (!ct) |
| 194 | return 0; | 194 | return 0; |
| @@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp, | |||
| 197 | switch (nf_ct_l3num(ct)) { | 197 | switch (nf_ct_l3num(ct)) { |
| 198 | case AF_INET: | 198 | case AF_INET: |
| 199 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); | 199 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); |
| 200 | if (ret == 0) | ||
| 201 | return 0; | ||
| 200 | break; | 202 | break; |
| 201 | case AF_INET6: | 203 | case AF_INET6: |
| 204 | if (cp < limit && *cp == '[') | ||
| 205 | cp++; | ||
| 206 | else if (delim) | ||
| 207 | return 0; | ||
| 208 | |||
| 202 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); | 209 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); |
| 210 | if (ret == 0) | ||
| 211 | return 0; | ||
| 212 | |||
| 213 | if (end < limit && *end == ']') | ||
| 214 | end++; | ||
| 215 | else if (delim) | ||
| 216 | return 0; | ||
| 203 | break; | 217 | break; |
| 204 | default: | 218 | default: |
| 205 | BUG(); | 219 | BUG(); |
| 206 | } | 220 | } |
| 207 | 221 | ||
| 208 | if (ret == 0 || end == cp) | ||
| 209 | return 0; | ||
| 210 | if (endp) | 222 | if (endp) |
| 211 | *endp = end; | 223 | *endp = end; |
| 212 | return 1; | 224 | return 1; |
| @@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, | |||
| 219 | union nf_inet_addr addr; | 231 | union nf_inet_addr addr; |
| 220 | const char *aux = dptr; | 232 | const char *aux = dptr; |
| 221 | 233 | ||
| 222 | if (!parse_addr(ct, dptr, &dptr, &addr, limit)) { | 234 | if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) { |
| 223 | pr_debug("ip: %s parse failed.!\n", dptr); | 235 | pr_debug("ip: %s parse failed.!\n", dptr); |
| 224 | return 0; | 236 | return 0; |
| 225 | } | 237 | } |
| @@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct, | |||
| 296 | return 0; | 308 | return 0; |
| 297 | dptr += shift; | 309 | dptr += shift; |
| 298 | 310 | ||
| 299 | if (!parse_addr(ct, dptr, &end, addr, limit)) | 311 | if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) |
| 300 | return -1; | 312 | return -1; |
| 301 | if (end < limit && *end == ':') { | 313 | if (end < limit && *end == ':') { |
| 302 | end++; | 314 | end++; |
| @@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, | |||
| 550 | if (ret == 0) | 562 | if (ret == 0) |
| 551 | return ret; | 563 | return ret; |
| 552 | 564 | ||
| 553 | if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit)) | 565 | if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) |
| 554 | return -1; | 566 | return -1; |
| 555 | if (*c == ':') { | 567 | if (*c == ':') { |
| 556 | c++; | 568 | c++; |
| @@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, | |||
| 599 | unsigned int dataoff, unsigned int datalen, | 611 | unsigned int dataoff, unsigned int datalen, |
| 600 | const char *name, | 612 | const char *name, |
| 601 | unsigned int *matchoff, unsigned int *matchlen, | 613 | unsigned int *matchoff, unsigned int *matchlen, |
| 602 | union nf_inet_addr *addr) | 614 | union nf_inet_addr *addr, bool delim) |
| 603 | { | 615 | { |
| 604 | const char *limit = dptr + datalen; | 616 | const char *limit = dptr + datalen; |
| 605 | const char *start, *end; | 617 | const char *start, *end; |
| @@ -613,7 +625,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, | |||
| 613 | return 0; | 625 | return 0; |
| 614 | 626 | ||
| 615 | start += strlen(name); | 627 | start += strlen(name); |
| 616 | if (!parse_addr(ct, start, &end, addr, limit)) | 628 | if (!sip_parse_addr(ct, start, &end, addr, limit, delim)) |
| 617 | return 0; | 629 | return 0; |
| 618 | *matchoff = start - dptr; | 630 | *matchoff = start - dptr; |
| 619 | *matchlen = end - start; | 631 | *matchlen = end - start; |
| @@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, | |||
| 675 | return 1; | 687 | return 1; |
| 676 | } | 688 | } |
| 677 | 689 | ||
| 690 | static int sdp_parse_addr(const struct nf_conn *ct, const char *cp, | ||
| 691 | const char **endp, union nf_inet_addr *addr, | ||
| 692 | const char *limit) | ||
| 693 | { | ||
| 694 | const char *end; | ||
| 695 | int ret; | ||
| 696 | |||
| 697 | memset(addr, 0, sizeof(*addr)); | ||
| 698 | switch (nf_ct_l3num(ct)) { | ||
| 699 | case AF_INET: | ||
| 700 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); | ||
| 701 | break; | ||
| 702 | case AF_INET6: | ||
| 703 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); | ||
| 704 | break; | ||
| 705 | default: | ||
| 706 | BUG(); | ||
| 707 | } | ||
| 708 | |||
| 709 | if (ret == 0) | ||
| 710 | return 0; | ||
| 711 | if (endp) | ||
| 712 | *endp = end; | ||
| 713 | return 1; | ||
| 714 | } | ||
| 715 | |||
| 716 | /* skip ip address. returns its length. */ | ||
| 717 | static int sdp_addr_len(const struct nf_conn *ct, const char *dptr, | ||
| 718 | const char *limit, int *shift) | ||
| 719 | { | ||
| 720 | union nf_inet_addr addr; | ||
| 721 | const char *aux = dptr; | ||
| 722 | |||
| 723 | if (!sdp_parse_addr(ct, dptr, &dptr, &addr, limit)) { | ||
| 724 | pr_debug("ip: %s parse failed.!\n", dptr); | ||
| 725 | return 0; | ||
| 726 | } | ||
| 727 | |||
| 728 | return dptr - aux; | ||
| 729 | } | ||
| 730 | |||
| 678 | /* SDP header parsing: a SDP session description contains an ordered set of | 731 | /* SDP header parsing: a SDP session description contains an ordered set of |
| 679 | * headers, starting with a section containing general session parameters, | 732 | * headers, starting with a section containing general session parameters, |
| 680 | * optionally followed by multiple media descriptions. | 733 | * optionally followed by multiple media descriptions. |
| @@ -686,10 +739,10 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, | |||
| 686 | */ | 739 | */ |
| 687 | static const struct sip_header ct_sdp_hdrs[] = { | 740 | static const struct sip_header ct_sdp_hdrs[] = { |
| 688 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), | 741 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), |
| 689 | [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len), | 742 | [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len), |
| 690 | [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), | 743 | [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len), |
| 691 | [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), | 744 | [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len), |
| 692 | [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), | 745 | [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len), |
| 693 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), | 746 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), |
| 694 | }; | 747 | }; |
| 695 | 748 | ||
| @@ -775,8 +828,8 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, | |||
| 775 | if (ret <= 0) | 828 | if (ret <= 0) |
| 776 | return ret; | 829 | return ret; |
| 777 | 830 | ||
| 778 | if (!parse_addr(ct, dptr + *matchoff, NULL, addr, | 831 | if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr, |
| 779 | dptr + *matchoff + *matchlen)) | 832 | dptr + *matchoff + *matchlen)) |
| 780 | return -1; | 833 | return -1; |
| 781 | return 1; | 834 | return 1; |
| 782 | } | 835 | } |
