History

netfilter: nf_ct_sip: fix IPv6 address parsing

Within SIP messages IPv6 addresses are enclosed in square brackets in most cases, with the exception of the "received=" header parameter. Currently the helper fails to parse enclosed addresses. This patch: - changes the SIP address parsing function to enforce square brackets when required, and accept them when not required but present, as recommended by RFC 5118. - adds a new SDP address parsing function that never accepts square brackets since SDP doesn't use them. With these changes, the SIP helper correctly parses all test messages from RFC 5118 (Session Initiation Protocol (SIP) Torture Test Messages for Internet Protocol Version 6 (IPv6)).

Patrick McHardy committed 14 years ago

Commit 02b69cb1 parent e9324b23 files · +73 −20Browse files

Unified · Split

3 files
  1. include/linux/netfilter/nf_conntrack_sip.h +1 −1
  2. net/ipv4/netfilter/nf_nat_sip.c +2 −2
  3. net/netfilter/nf_conntrack_sip.c +70 −17
include/linux/netfilter/nf_conntrack_sip.h+1−1
@@ -164,7 +164,7 @@ extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr · 163 unmodified lines
164164 unsigned int dataoff, unsigned int datalen,
165165 const char *name,
166166 unsigned int *matchoff, unsigned int *matchlen,
167− union nf_inet_addr *addr);
167+ union nf_inet_addr *addr, bool delim);
168168 extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
169169 unsigned int off, unsigned int datalen,
170170 const char *name,
net/ipv4/netfilter/nf_nat_sip.c+2−2
@@ -173,7 +173,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, · 172 unmodified lines
173173 * the reply. */
174174 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
175175 "maddr=", &poff, &plen,
176− &addr) > 0 &&
176+ &addr, true) > 0 &&
177177 addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
178178 addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
179179 buflen = sprintf(buffer, "%pI4",
@@ -187,7 +187,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, · 7 unmodified lines
187187 * from which the server received the request. */
188188 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
189189 "received=", &poff, &plen,
190− &addr) > 0 &&
190+ &addr, false) > 0 &&
191191 addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
192192 addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
193193 buflen = sprintf(buffer, "%pI4",
net/netfilter/nf_conntrack_sip.c+70−17
@@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr, · 182 unmodified lines
183183 return len + digits_len(ct, dptr, limit, shift);
184184 }
185185
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)
189189 {
190190 const char *end;
191− int ret = 0;
191+ int ret;
192192
193193 if (!ct)
194194 return 0;
@@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp, · 2 unmodified lines
197197 switch (nf_ct_l3num(ct)) {
198198 case AF_INET:
199199 ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
200+ if (ret == 0)
201+ return 0;
200202 break;
201203 case AF_INET6:
204+ if (cp < limit && *cp == '[')
205+ cp++;
206+ else if (delim)
207+ return 0;
208+
202209 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;
203217 break;
204218 default:
205219 BUG();
206220 }
207221
208− if (ret == 0 || end == cp)
209− return 0;
210222 if (endp)
211223 *endp = end;
212224 return 1;
@@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr, · 6 unmodified lines
219231 union nf_inet_addr addr;
220232 const char *aux = dptr;
221233
222− if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
234+ if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) {
223235 pr_debug("ip: %s parse failed.!\n", dptr);
224236 return 0;
225237 }
@@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct, · 70 unmodified lines
296308 return 0;
297309 dptr += shift;
298310
299− if (!parse_addr(ct, dptr, &end, addr, limit))
311+ if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
300312 return -1;
301313 if (end < limit && *end == ':') {
302314 end++;
@@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, · 247 unmodified lines
550562 if (ret == 0)
551563 return ret;
552564
553− if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit))
565+ if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
554566 return -1;
555567 if (*c == ':') {
556568 c++;
@@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, · 42 unmodified lines
599611 unsigned int dataoff, unsigned int datalen,
600612 const char *name,
601613 unsigned int *matchoff, unsigned int *matchlen,
602− union nf_inet_addr *addr)
614+ union nf_inet_addr *addr, bool delim)
603615 {
604616 const char *limit = dptr + datalen;
605617 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
613625 return 0;
614626
615627 start += strlen(name);
616− if (!parse_addr(ct, start, &end, addr, limit))
628+ if (!sip_parse_addr(ct, start, &end, addr, limit, delim))
617629 return 0;
618630 *matchoff = start - dptr;
619631 *matchlen = end - start;
@@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, · 55 unmodified lines
675687 return 1;
676688 }
677689
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+
678731 /* SDP header parsing: a SDP session description contains an ordered set of
679732 * headers, starting with a section containing general session parameters,
680733 * 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
686739 */
687740 static const struct sip_header ct_sdp_hdrs[] = {
688741 [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),
693746 [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len),
694747 };
695748
@@ -775,8 +828,8 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, · 79 unmodified lines
775828 if (ret <= 0)
776829 return ret;
777830
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))
780833 return -1;
781834 return 1;
782835 }