| @@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr, · 182 unmodified lines |
| 183 | 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, |
| 187 | | − const char **endp, union nf_inet_addr *addr, |
| 188 | | − const char *limit) |
| 186 | +static int sip_parse_addr(const struct nf_conn *ct, const char *cp, |
| 187 | + const char **endp, union nf_inet_addr *addr, |
| 188 | + const char *limit, bool delim) |
| 189 | 189 | { |
| 190 | 190 | const char *end; |
| 191 | | − int ret = 0; |
| 191 | + int ret; |
| 192 | 192 | |
| 193 | 193 | if (!ct) |
| 194 | 194 | return 0; |
| @@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp, · 2 unmodified lines |
| 197 | 197 | switch (nf_ct_l3num(ct)) { |
| 198 | 198 | case AF_INET: |
| 199 | 199 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); |
| 200 | + if (ret == 0) |
| 201 | + return 0; |
| 200 | 202 | break; |
| 201 | 203 | case AF_INET6: |
| 204 | + if (cp < limit && *cp == '[') |
| 205 | + cp++; |
| 206 | + else if (delim) |
| 207 | + return 0; |
| 208 | + |
| 202 | 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 | 217 | break; |
| 204 | 218 | default: |
| 205 | 219 | BUG(); |
| 206 | 220 | } |
| 207 | 221 | |
| 208 | | − if (ret == 0 || end == cp) |
| 209 | | − return 0; |
| 210 | 222 | if (endp) |
| 211 | 223 | *endp = end; |
| 212 | 224 | return 1; |
| @@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, · 6 unmodified lines |
| 219 | 231 | union nf_inet_addr addr; |
| 220 | 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 | 235 | pr_debug("ip: %s parse failed.!\n", dptr); |
| 224 | 236 | return 0; |
| 225 | 237 | } |
| @@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct, · 70 unmodified lines |
| 296 | 308 | return 0; |
| 297 | 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 | 312 | return -1; |
| 301 | 313 | if (end < limit && *end == ':') { |
| 302 | 314 | end++; |
| @@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, · 247 unmodified lines |
| 550 | 562 | if (ret == 0) |
| 551 | 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 | 566 | return -1; |
| 555 | 567 | if (*c == ':') { |
| 556 | 568 | c++; |
| @@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, · 42 unmodified lines |
| 599 | 611 | unsigned int dataoff, unsigned int datalen, |
| 600 | 612 | const char *name, |
| 601 | 613 | unsigned int *matchoff, unsigned int *matchlen, |
| 602 | | − union nf_inet_addr *addr) |
| 614 | + union nf_inet_addr *addr, bool delim) |
| 603 | 615 | { |
| 604 | 616 | const char *limit = dptr + datalen; |
| 605 | 617 | const char *start, *end; |
| @@ -613,7 +625,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, · 7 unmodified lines |
| 613 | 625 | return 0; |
| 614 | 626 | |
| 615 | 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 | 629 | return 0; |
| 618 | 630 | *matchoff = start - dptr; |
| 619 | 631 | *matchlen = end - start; |
| @@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, · 55 unmodified lines |
| 675 | 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 | 731 | /* SDP header parsing: a SDP session description contains an ordered set of |
| 679 | 732 | * headers, starting with a section containing general session parameters, |
| 680 | 733 | * optionally followed by multiple media descriptions. |
| @@ -686,10 +739,10 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, · 5 unmodified lines |
| 686 | 739 | */ |
| 687 | 740 | static const struct sip_header ct_sdp_hdrs[] = { |
| 688 | 741 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), |
| 689 | | − [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len), |
| 690 | | − [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), |
| 691 | | − [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), |
| 692 | | − [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), |
| 742 | + [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len), |
| 743 | + [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len), |
| 744 | + [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len), |
| 745 | + [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len), |
| 693 | 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, · 79 unmodified lines |
| 775 | 828 | if (ret <= 0) |
| 776 | 829 | return ret; |
| 777 | 830 | |
| 778 | | − if (!parse_addr(ct, dptr + *matchoff, NULL, addr, |
| 779 | | − dptr + *matchoff + *matchlen)) |
| 831 | + if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr, |
| 832 | + dptr + *matchoff + *matchlen)) |
| 780 | 833 | return -1; |
| 781 | 834 | return 1; |
| 782 | 835 | } |