aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-03-25 23:16:54 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-25 23:16:54 -0400
commit2a6cfb22ae002330d445f734668d9158db9e90de (patch)
tree5d05dcfcfdc1df571b5c502b5df314debd7a19ce /net/ipv4
parentb1ec488b1fb3c7a8819857e3506787516ca1ed4d (diff)
[NETFILTER]: nf_conntrack_sip: adjust dptr and datalen after packet mangling
After mangling the packet, the pointer to the data and the length of the data portion may change and need to be adjusted. Use double data pointers and a pointer to the length everywhere and add a helper function to the NAT helper for performing the adjustments. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c91
1 files changed, 48 insertions, 43 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 84d8b4982c..e77122e652 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 }