diff options
-rw-r--r-- | include/linux/netfilter/nf_conntrack_sip.h | 6 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 91 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 14 |
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 { | |||
24 | extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, | 24 | extern 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); | ||
28 | extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, | 29 | extern 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 | ||
33 | extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, | 35 | extern 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 | ||
63 | static 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 | |||
63 | static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, | 81 | static 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 | ||
95 | static unsigned int ip_nat_sip(struct sk_buff *skb, | 111 | static 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, | |||
136 | static unsigned int mangle_sip_packet(struct sk_buff *skb, | 149 | static 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 | ||
157 | static int mangle_content_len(struct sk_buff *skb, | 166 | static 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 | ||
219 | static void ip_nat_sdp_expect(struct nf_conn *ct, | 224 | static void ip_nat_sdp_expect(struct nf_conn *ct, |
@@ -242,7 +247,7 @@ static void ip_nat_sdp_expect(struct nf_conn *ct, | |||
242 | static unsigned int ip_nat_sdp(struct sk_buff *skb, | 247 | static 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"); | |||
39 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, | 39 | unsigned 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; | ||
43 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); | 44 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); |
44 | 45 | ||
45 | unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, | 46 | unsigned 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; | ||
49 | EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); | 51 | EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); |
50 | 52 | ||
51 | static int digits_len(const struct nf_conn *, const char *, const char *, int *); | 53 | static 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 | } |
472 | out: | 474 | out: |