Przeglądaj źródła

[NETFILTER]: sip conntrack: do case insensitive SIP header search

SIP headers are generally case-insensitive, only SDP headers are
case sensitive.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Patrick McHardy 18 lat temu
rodzic
commit
40883e8184

+ 2 - 1
include/linux/netfilter_ipv4/ip_conntrack_sip.h

@@ -31,6 +31,7 @@ extern int ct_sip_get_info(const char *dptr, size_t dlen,
 			   enum sip_header_pos pos);
 extern int ct_sip_lnlen(const char *line, const char *limit);
 extern const char *ct_sip_search(const char *needle, const char *haystack,
-                                 size_t needle_len, size_t haystack_len);
+				 size_t needle_len, size_t haystack_len,
+				 int case_sensitive);
 #endif /* __KERNEL__ */
 #endif /* __IP_CONNTRACK_SIP_H__ */

+ 16 - 4
net/ipv4/netfilter/ip_conntrack_sip.c

@@ -64,6 +64,7 @@ struct sip_header_nfo {
 	size_t		lnlen;
 	size_t		snlen;
 	size_t		ln_strlen;
+	int		case_sensitive;
 	int		(*match_len)(const char *, const char *, int *);
 };
 
@@ -105,6 +106,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = {
 		.match_len	= skp_digits_len
 	},
 	[POS_MEDIA] = {		/* SDP media info */
+		.case_sensitive	= 1,
 		.lname		= "\nm=",
 		.lnlen		= sizeof("\nm=") - 1,
 		.sname		= "\rm=",
@@ -114,6 +116,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = {
 		.match_len	= digits_len
 	},
 	[POS_OWNER] = { 	/* SDP owner address*/
+		.case_sensitive	= 1,
 		.lname		= "\no=",
 		.lnlen		= sizeof("\no=") - 1,
 		.sname		= "\ro=",
@@ -123,6 +126,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = {
 		.match_len	= epaddr_len
 	},
 	[POS_CONNECTION] = { 	/* SDP connection info */
+		.case_sensitive	= 1,
 		.lname		= "\nc=",
 		.lnlen		= sizeof("\nc=") - 1,
 		.sname		= "\rc=",
@@ -132,6 +136,7 @@ static struct sip_header_nfo ct_sip_hdrs[] = {
 		.match_len	= epaddr_len
 	},
 	[POS_SDP_HEADER] = { 	/* SDP version header */
+		.case_sensitive	= 1,
 		.lname		= "\nv=",
 		.lnlen		= sizeof("\nv=") - 1,
 		.sname		= "\rv=",
@@ -161,13 +166,19 @@ EXPORT_SYMBOL_GPL(ct_sip_lnlen);
 
 /* Linear string search, case sensitive. */
 const char *ct_sip_search(const char *needle, const char *haystack,
-                          size_t needle_len, size_t haystack_len)
+			  size_t needle_len, size_t haystack_len,
+			  int case_sensitive)
 {
 	const char *limit = haystack + (haystack_len - needle_len);
 
 	while (haystack <= limit) {
-		if (memcmp(haystack, needle, needle_len) == 0)
-			return haystack;
+		if (case_sensitive) {
+			if (strncmp(haystack, needle, needle_len) == 0)
+				return haystack;
+		} else {
+			if (strnicmp(haystack, needle, needle_len) == 0)
+				return haystack;
+		}
 		haystack++;
 	}
 	return NULL;
@@ -280,7 +291,8 @@ int ct_sip_get_info(const char *dptr, size_t dlen,
 			continue;
 		}
 		aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
-		                    ct_sip_lnlen(dptr, limit));
+		                    ct_sip_lnlen(dptr, limit),
+				    hnfo->case_sensitive);
 		if (!aux) {
 			DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str,
 			       hnfo->lname);

+ 4 - 3
net/ipv4/netfilter/ip_nat_sip.c

@@ -87,14 +87,15 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb,
 		                       buffer, bufflen, POS_VIA))
 			return 0;
 
-		/* This search should ignore case, but later.. */
 		aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1,
-		                    (*pskb)->len - dataoff);
+		                    (*pskb)->len - dataoff, 0);
 		if (!aux)
 			return 0;
 
 		if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"),
-		    ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff)))
+				   ct_sip_lnlen(aux,
+				   		*dptr + (*pskb)->len - dataoff),
+				   1))
 			return 1;
 
 		return mangle_sip_packet(pskb, ctinfo, ct, dptr,