aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/nf_conntrack_sip.h6
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c91
-rw-r--r--net/netfilter/nf_conntrack_sip.c14
3 files changed, 60 insertions, 51 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 8e5ce1ca7bfc..9d0dbfb26300 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -24,11 +24,13 @@ enum sip_header_pos {
24extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, 24extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
25 enum ip_conntrack_info ctinfo, 25 enum ip_conntrack_info ctinfo,
26 struct nf_conn *ct, 26 struct nf_conn *ct,
27 const char **dptr); 27 const char **dptr,
28 unsigned int *datalen);
28extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, 29extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
29 enum ip_conntrack_info ctinfo, 30 enum ip_conntrack_info ctinfo,
30 struct nf_conntrack_expect *exp, 31 struct nf_conntrack_expect *exp,
31 const char *dptr); 32 const char **dptr,
33 unsigned int *datalen);
32 34
33extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, 35extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr,
34 size_t dlen, unsigned int *matchoff, 36 size_t dlen, unsigned int *matchoff,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 84d8b4982cdf..e77122e65283 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -60,15 +60,35 @@ static void addr_map_init(const struct nf_conn *ct, struct addr_map *map)
60 } 60 }
61} 61}
62 62
63static unsigned int mangle_packet(struct sk_buff *skb,
64 const char **dptr, unsigned int *datalen,
65 unsigned int matchoff, unsigned int matchlen,
66 const char *buffer, unsigned int buflen)
67{
68 enum ip_conntrack_info ctinfo;
69 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
70
71 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen,
72 buffer, buflen))
73 return 0;
74
75 /* Reload data pointer and adjust datalen value */
76 *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
77 *datalen += buflen - matchlen;
78 return 1;
79}
80
63static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 81static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
64 struct nf_conn *ct, const char **dptr, size_t dlen, 82 struct nf_conn *ct,
83 const char **dptr, unsigned int *datalen,
65 enum sip_header_pos pos, struct addr_map *map) 84 enum sip_header_pos pos, struct addr_map *map)
66{ 85{
67 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 86 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
68 unsigned int matchlen, matchoff, addrlen; 87 unsigned int matchlen, matchoff, addrlen;
69 char *addr; 88 char *addr;
70 89
71 if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) 90 if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
91 pos) <= 0)
72 return 1; 92 return 1;
73 93
74 if ((matchlen == map->addr[dir].srciplen || 94 if ((matchlen == map->addr[dir].srciplen ||
@@ -84,26 +104,19 @@ static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
84 } else 104 } else
85 return 1; 105 return 1;
86 106
87 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, 107 return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
88 matchoff, matchlen, addr, addrlen)) 108 addr, addrlen);
89 return 0;
90 *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
91 return 1;
92
93} 109}
94 110
95static unsigned int ip_nat_sip(struct sk_buff *skb, 111static unsigned int ip_nat_sip(struct sk_buff *skb,
96 enum ip_conntrack_info ctinfo, 112 enum ip_conntrack_info ctinfo,
97 struct nf_conn *ct, 113 struct nf_conn *ct,
98 const char **dptr) 114 const char **dptr, unsigned int *datalen)
99{ 115{
100 enum sip_header_pos pos; 116 enum sip_header_pos pos;
101 struct addr_map map; 117 struct addr_map map;
102 int dataoff, datalen;
103 118
104 dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); 119 if (*datalen < sizeof("SIP/2.0") - 1)
105 datalen = skb->len - dataoff;
106 if (datalen < sizeof("SIP/2.0") - 1)
107 return NF_ACCEPT; 120 return NF_ACCEPT;
108 121
109 addr_map_init(ct, &map); 122 addr_map_init(ct, &map);
@@ -115,7 +128,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
115 * The "userinfo" and "@" components of the SIP URI MUST NOT 128 * The "userinfo" and "@" components of the SIP URI MUST NOT
116 * be present. 129 * be present.
117 */ 130 */
118 if (datalen >= sizeof("REGISTER") - 1 && 131 if (*datalen >= sizeof("REGISTER") - 1 &&
119 strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) 132 strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0)
120 pos = POS_REG_REQ_URI; 133 pos = POS_REG_REQ_URI;
121 else 134 else
@@ -136,51 +149,45 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
136static unsigned int mangle_sip_packet(struct sk_buff *skb, 149static unsigned int mangle_sip_packet(struct sk_buff *skb,
137 enum ip_conntrack_info ctinfo, 150 enum ip_conntrack_info ctinfo,
138 struct nf_conn *ct, 151 struct nf_conn *ct,
139 const char **dptr, size_t dlen, 152 const char **dptr, unsigned int *datalen,
140 char *buffer, int bufflen, 153 char *buffer, int bufflen,
141 enum sip_header_pos pos) 154 enum sip_header_pos pos)
142{ 155{
143 unsigned int matchlen, matchoff; 156 unsigned int matchlen, matchoff;
144 157
145 if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) 158 if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen,
146 return 0; 159 pos) <= 0)
147
148 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
149 matchoff, matchlen, buffer, bufflen))
150 return 0; 160 return 0;
151 161
152 /* We need to reload this. Thanks Patrick. */ 162 return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
153 *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); 163 buffer, bufflen);
154 return 1;
155} 164}
156 165
157static int mangle_content_len(struct sk_buff *skb, 166static int mangle_content_len(struct sk_buff *skb,
158 enum ip_conntrack_info ctinfo, 167 enum ip_conntrack_info ctinfo,
159 struct nf_conn *ct, 168 struct nf_conn *ct,
160 const char *dptr) 169 const char **dptr, unsigned int *datalen)
161{ 170{
162 unsigned int dataoff, matchoff, matchlen; 171 unsigned int matchoff, matchlen;
163 char buffer[sizeof("65536")]; 172 char buffer[sizeof("65536")];
164 int bufflen; 173 int bufflen;
165 174
166 dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
167
168 /* Get actual SDP length */ 175 /* Get actual SDP length */
169 if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, 176 if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff,
170 &matchlen, POS_SDP_HEADER) > 0) { 177 &matchlen, POS_SDP_HEADER) > 0) {
171 178
172 /* since ct_sip_get_info() give us a pointer passing 'v=' 179 /* since ct_sip_get_info() give us a pointer passing 'v='
173 we need to add 2 bytes in this count. */ 180 we need to add 2 bytes in this count. */
174 int c_len = skb->len - dataoff - matchoff + 2; 181 int c_len = *datalen - matchoff + 2;
175 182
176 /* Now, update SDP length */ 183 /* Now, update SDP length */
177 if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, 184 if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff,
178 &matchlen, POS_CONTENT) > 0) { 185 &matchlen, POS_CONTENT) > 0) {
179 186
180 bufflen = sprintf(buffer, "%u", c_len); 187 bufflen = sprintf(buffer, "%u", c_len);
181 return nf_nat_mangle_udp_packet(skb, ct, ctinfo, 188 return mangle_packet(skb, dptr, datalen,
182 matchoff, matchlen, 189 matchoff, matchlen,
183 buffer, bufflen); 190 buffer, bufflen);
184 } 191 }
185 } 192 }
186 return 0; 193 return 0;
@@ -190,30 +197,28 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
190 enum ip_conntrack_info ctinfo, 197 enum ip_conntrack_info ctinfo,
191 struct nf_conn *ct, 198 struct nf_conn *ct,
192 __be32 newip, u_int16_t port, 199 __be32 newip, u_int16_t port,
193 const char *dptr) 200 const char **dptr, unsigned int *datalen)
194{ 201{
195 char buffer[sizeof("nnn.nnn.nnn.nnn")]; 202 char buffer[sizeof("nnn.nnn.nnn.nnn")];
196 unsigned int dataoff, bufflen; 203 unsigned int bufflen;
197
198 dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
199 204
200 /* Mangle owner and contact info. */ 205 /* Mangle owner and contact info. */
201 bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); 206 bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
202 if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, 207 if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
203 buffer, bufflen, POS_OWNER_IP4)) 208 buffer, bufflen, POS_OWNER_IP4))
204 return 0; 209 return 0;
205 210
206 if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, 211 if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
207 buffer, bufflen, POS_CONNECTION_IP4)) 212 buffer, bufflen, POS_CONNECTION_IP4))
208 return 0; 213 return 0;
209 214
210 /* Mangle media port. */ 215 /* Mangle media port. */
211 bufflen = sprintf(buffer, "%u", port); 216 bufflen = sprintf(buffer, "%u", port);
212 if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, 217 if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen,
213 buffer, bufflen, POS_MEDIA)) 218 buffer, bufflen, POS_MEDIA))
214 return 0; 219 return 0;
215 220
216 return mangle_content_len(skb, ctinfo, ct, dptr); 221 return mangle_content_len(skb, ctinfo, ct, dptr, datalen);
217} 222}
218 223
219static void ip_nat_sdp_expect(struct nf_conn *ct, 224static void ip_nat_sdp_expect(struct nf_conn *ct,
@@ -242,7 +247,7 @@ static void ip_nat_sdp_expect(struct nf_conn *ct,
242static unsigned int ip_nat_sdp(struct sk_buff *skb, 247static unsigned int ip_nat_sdp(struct sk_buff *skb,
243 enum ip_conntrack_info ctinfo, 248 enum ip_conntrack_info ctinfo,
244 struct nf_conntrack_expect *exp, 249 struct nf_conntrack_expect *exp,
245 const char *dptr) 250 const char **dptr, unsigned int *datalen)
246{ 251{
247 struct nf_conn *ct = exp->master; 252 struct nf_conn *ct = exp->master;
248 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 253 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -275,7 +280,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
275 if (port == 0) 280 if (port == 0)
276 return NF_DROP; 281 return NF_DROP;
277 282
278 if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr)) { 283 if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
279 nf_ct_unexpect_related(exp); 284 nf_ct_unexpect_related(exp);
280 return NF_DROP; 285 return NF_DROP;
281 } 286 }
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 016e1c1aafe4..fa0d5599ff24 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -39,13 +39,15 @@ MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
39unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, 39unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
40 enum ip_conntrack_info ctinfo, 40 enum ip_conntrack_info ctinfo,
41 struct nf_conn *ct, 41 struct nf_conn *ct,
42 const char **dptr) __read_mostly; 42 const char **dptr,
43 unsigned int *datalen) __read_mostly;
43EXPORT_SYMBOL_GPL(nf_nat_sip_hook); 44EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
44 45
45unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, 46unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
46 enum ip_conntrack_info ctinfo, 47 enum ip_conntrack_info ctinfo,
47 struct nf_conntrack_expect *exp, 48 struct nf_conntrack_expect *exp,
48 const char *dptr) __read_mostly; 49 const char **dptr,
50 unsigned int *datalen) __read_mostly;
49EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); 51EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
50 52
51static int digits_len(const struct nf_conn *, const char *, const char *, int *); 53static int digits_len(const struct nf_conn *, const char *, const char *, int *);
@@ -369,7 +371,7 @@ static int set_expected_rtp(struct sk_buff *skb,
369 enum ip_conntrack_info ctinfo, 371 enum ip_conntrack_info ctinfo,
370 union nf_inet_addr *addr, 372 union nf_inet_addr *addr,
371 __be16 port, 373 __be16 port,
372 const char *dptr) 374 const char **dptr, unsigned int *datalen)
373{ 375{
374 struct nf_conntrack_expect *exp; 376 struct nf_conntrack_expect *exp;
375 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 377 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -386,7 +388,7 @@ static int set_expected_rtp(struct sk_buff *skb,
386 388
387 nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); 389 nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
388 if (nf_nat_sdp && ct->status & IPS_NAT_MASK) 390 if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
389 ret = nf_nat_sdp(skb, ctinfo, exp, dptr); 391 ret = nf_nat_sdp(skb, ctinfo, exp, dptr, datalen);
390 else { 392 else {
391 if (nf_ct_expect_related(exp) != 0) 393 if (nf_ct_expect_related(exp) != 0)
392 ret = NF_DROP; 394 ret = NF_DROP;
@@ -429,7 +431,7 @@ static int sip_help(struct sk_buff *skb,
429 431
430 nf_nat_sip = rcu_dereference(nf_nat_sip_hook); 432 nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
431 if (nf_nat_sip && ct->status & IPS_NAT_MASK) { 433 if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
432 if (!nf_nat_sip(skb, ctinfo, ct, &dptr)) { 434 if (!nf_nat_sip(skb, ctinfo, ct, &dptr, &datalen)) {
433 ret = NF_DROP; 435 ret = NF_DROP;
434 goto out; 436 goto out;
435 } 437 }
@@ -466,7 +468,7 @@ static int sip_help(struct sk_buff *skb,
466 goto out; 468 goto out;
467 } 469 }
468 ret = set_expected_rtp(skb, ct, ctinfo, &addr, 470 ret = set_expected_rtp(skb, ct, ctinfo, &addr,
469 htons(port), dptr); 471 htons(port), &dptr, &datalen);
470 } 472 }
471 } 473 }
472out: 474out: