aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/nf_conntrack_sip.h5
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c46
-rw-r--r--net/netfilter/nf_conntrack_sip.c64
3 files changed, 77 insertions, 38 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 9131cbc9b9de..480b26f40ce4 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -6,8 +6,6 @@
6#define SIP_TIMEOUT 3600 6#define SIP_TIMEOUT 3600
7 7
8enum sip_header_pos { 8enum sip_header_pos {
9 POS_REG_REQ_URI,
10 POS_REQ_URI,
11 POS_FROM, 9 POS_FROM,
12 POS_TO, 10 POS_TO,
13 POS_VIA, 11 POS_VIA,
@@ -59,6 +57,9 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
59 unsigned int *datalen, 57 unsigned int *datalen,
60 struct nf_conntrack_expect *exp); 58 struct nf_conntrack_expect *exp);
61 59
60extern int ct_sip_parse_request(const struct nf_conn *ct,
61 const char *dptr, unsigned int datalen,
62 unsigned int *matchoff, unsigned int *matchlen);
62extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, 63extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
63 size_t dlen, unsigned int *matchoff, 64 size_t dlen, unsigned int *matchoff,
64 unsigned int *matchlen, enum sip_header_pos pos); 65 unsigned int *matchlen, enum sip_header_pos pos);
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index aa8a4f492baf..60151b5901a5 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -78,20 +78,17 @@ static unsigned int mangle_packet(struct sk_buff *skb,
78 return 1; 78 return 1;
79} 79}
80 80
81static int map_sip_addr(struct sk_buff *skb, 81static int map_addr(struct sk_buff *skb,
82 const char **dptr, unsigned int *datalen, 82 const char **dptr, unsigned int *datalen,
83 enum sip_header_pos pos, struct addr_map *map) 83 unsigned int matchoff, unsigned int matchlen,
84 struct addr_map *map)
84{ 85{
85 enum ip_conntrack_info ctinfo; 86 enum ip_conntrack_info ctinfo;
86 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 87 struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo);
87 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 88 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
88 unsigned int matchlen, matchoff, addrlen; 89 unsigned int addrlen;
89 char *addr; 90 char *addr;
90 91
91 if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
92 pos) <= 0)
93 return 1;
94
95 if ((matchlen == map->addr[dir].srciplen || 92 if ((matchlen == map->addr[dir].srciplen ||
96 matchlen == map->addr[dir].srclen) && 93 matchlen == map->addr[dir].srclen) &&
97 strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { 94 strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
@@ -109,13 +106,27 @@ static int map_sip_addr(struct sk_buff *skb,
109 addr, addrlen); 106 addr, addrlen);
110} 107}
111 108
109static int map_sip_addr(struct sk_buff *skb,
110 const char **dptr, unsigned int *datalen,
111 enum sip_header_pos pos, struct addr_map *map)
112{
113 enum ip_conntrack_info ctinfo;
114 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
115 unsigned int matchlen, matchoff;
116
117 if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
118 pos) <= 0)
119 return 1;
120 return map_addr(skb, dptr, datalen, matchoff, matchlen, map);
121}
122
112static unsigned int ip_nat_sip(struct sk_buff *skb, 123static unsigned int ip_nat_sip(struct sk_buff *skb,
113 const char **dptr, unsigned int *datalen) 124 const char **dptr, unsigned int *datalen)
114{ 125{
115 enum ip_conntrack_info ctinfo; 126 enum ip_conntrack_info ctinfo;
116 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 127 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
117 enum sip_header_pos pos;
118 struct addr_map map; 128 struct addr_map map;
129 unsigned int matchoff, matchlen;
119 130
120 if (*datalen < strlen("SIP/2.0")) 131 if (*datalen < strlen("SIP/2.0"))
121 return NF_ACCEPT; 132 return NF_ACCEPT;
@@ -124,18 +135,9 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
124 135
125 /* Basic rules: requests and responses. */ 136 /* Basic rules: requests and responses. */
126 if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { 137 if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
127 /* 10.2: Constructing the REGISTER Request: 138 if (ct_sip_parse_request(ct, *dptr, *datalen,
128 * 139 &matchoff, &matchlen) > 0 &&
129 * The "userinfo" and "@" components of the SIP URI MUST NOT 140 !map_addr(skb, dptr, datalen, matchoff, matchlen, &map))
130 * be present.
131 */
132 if (*datalen >= strlen("REGISTER") &&
133 strnicmp(*dptr, "REGISTER", strlen("REGISTER")) == 0)
134 pos = POS_REG_REQ_URI;
135 else
136 pos = POS_REQ_URI;
137
138 if (!map_sip_addr(skb, dptr, datalen, pos, &map))
139 return NF_DROP; 141 return NF_DROP;
140 } 142 }
141 143
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 801fcb3c749f..bb4396155681 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -65,20 +65,6 @@ struct sip_header_nfo {
65}; 65};
66 66
67static const struct sip_header_nfo ct_sip_hdrs[] = { 67static const struct sip_header_nfo ct_sip_hdrs[] = {
68 [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */
69 .lname = "sip:",
70 .lnlen = sizeof("sip:") - 1,
71 .ln_str = ":",
72 .ln_strlen = sizeof(":") - 1,
73 .match_len = epaddr_len,
74 },
75 [POS_REQ_URI] = { /* SIP request URI */
76 .lname = "sip:",
77 .lnlen = sizeof("sip:") - 1,
78 .ln_str = "@",
79 .ln_strlen = sizeof("@") - 1,
80 .match_len = epaddr_len,
81 },
82 [POS_FROM] = { /* SIP From header */ 68 [POS_FROM] = { /* SIP From header */
83 .lname = "From:", 69 .lname = "From:",
84 .lnlen = sizeof("From:") - 1, 70 .lnlen = sizeof("From:") - 1,
@@ -164,6 +150,18 @@ const char *ct_sip_search(const char *needle, const char *haystack,
164} 150}
165EXPORT_SYMBOL_GPL(ct_sip_search); 151EXPORT_SYMBOL_GPL(ct_sip_search);
166 152
153static int string_len(const struct nf_conn *ct, const char *dptr,
154 const char *limit, int *shift)
155{
156 int len = 0;
157
158 while (dptr < limit && isalpha(*dptr)) {
159 dptr++;
160 len++;
161 }
162 return len;
163}
164
167static int digits_len(const struct nf_conn *ct, const char *dptr, 165static int digits_len(const struct nf_conn *ct, const char *dptr,
168 const char *limit, int *shift) 166 const char *limit, int *shift)
169{ 167{
@@ -258,6 +256,44 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
258 return epaddr_len(ct, dptr, limit, shift); 256 return epaddr_len(ct, dptr, limit, shift);
259} 257}
260 258
259/* Parse a SIP request line of the form:
260 *
261 * Request-Line = Method SP Request-URI SP SIP-Version CRLF
262 *
263 * and return the offset and length of the address contained in the Request-URI.
264 */
265int ct_sip_parse_request(const struct nf_conn *ct,
266 const char *dptr, unsigned int datalen,
267 unsigned int *matchoff, unsigned int *matchlen)
268{
269 const char *start = dptr, *limit = dptr + datalen;
270 unsigned int mlen;
271 int shift = 0;
272
273 /* Skip method and following whitespace */
274 mlen = string_len(ct, dptr, limit, NULL);
275 if (!mlen)
276 return 0;
277 dptr += mlen;
278 if (++dptr >= limit)
279 return 0;
280
281 /* Find SIP URI */
282 limit -= strlen("sip:");
283 for (; dptr < limit; dptr++) {
284 if (*dptr == '\r' || *dptr == '\n')
285 return -1;
286 if (strnicmp(dptr, "sip:", strlen("sip:")) == 0)
287 break;
288 }
289 *matchlen = skp_epaddr_len(ct, dptr, limit, &shift);
290 if (!*matchlen)
291 return 0;
292 *matchoff = dptr - start + shift;
293 return 1;
294}
295EXPORT_SYMBOL_GPL(ct_sip_parse_request);
296
261/* Returns 0 if not found, -1 error parsing. */ 297/* Returns 0 if not found, -1 error parsing. */
262int ct_sip_get_info(const struct nf_conn *ct, 298int ct_sip_get_info(const struct nf_conn *ct,
263 const char *dptr, size_t dlen, 299 const char *dptr, size_t dlen,