finally move buildroot-ng to trunk
[openwrt/staging/dedeckeh.git] / target / linux / generic-2.4 / patches / 603-netfilter_nat_pptp.patch
1 diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h
2 --- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h 2005-04-02 19:04:11.000000000 +0200
3 +++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h 2005-04-02 19:41:05.000000000 +0200
4 @@ -50,16 +50,19 @@
5
6 #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
7 #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
8 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
9
10 /* per conntrack: protocol private data */
11 union ip_conntrack_proto {
12 /* insert conntrack proto private data here */
13 struct ip_ct_tcp tcp;
14 struct ip_ct_icmp icmp;
15 + struct ip_ct_gre gre;
16 };
17
18 union ip_conntrack_expect_proto {
19 /* insert expect proto private data here */
20 + struct ip_ct_gre_expect gre;
21 };
22
23 /* Add protocol helper include file here */
24 @@ -67,6 +70,7 @@
25
26 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
27 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
28 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
29
30 /* per expectation: application helper private data */
31 union ip_conntrack_expect_help {
32 @@ -74,6 +78,7 @@
33 struct ip_ct_amanda_expect exp_amanda_info;
34 struct ip_ct_ftp_expect exp_ftp_info;
35 struct ip_ct_irc_expect exp_irc_info;
36 + struct ip_ct_pptp_expect exp_pptp_info;
37
38 #ifdef CONFIG_IP_NF_NAT_NEEDED
39 union {
40 @@ -87,14 +92,17 @@
41 /* insert conntrack helper private data (master) here */
42 struct ip_ct_ftp_master ct_ftp_info;
43 struct ip_ct_irc_master ct_irc_info;
44 + struct ip_ct_pptp_master ct_pptp_info;
45 };
46
47 #ifdef CONFIG_IP_NF_NAT_NEEDED
48 #include <linux/netfilter_ipv4/ip_nat.h>
49 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
50
51 /* per conntrack: nat application helper private data */
52 union ip_conntrack_nat_help {
53 /* insert nat helper private data here */
54 + struct ip_nat_pptp nat_pptp_info;
55 };
56 #endif
57
58 diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
59 --- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1970-01-01 01:00:00.000000000 +0100
60 +++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2005-04-02 19:09:07.000000000 +0200
61 @@ -0,0 +1,313 @@
62 +/* PPTP constants and structs */
63 +#ifndef _CONNTRACK_PPTP_H
64 +#define _CONNTRACK_PPTP_H
65 +
66 +/* state of the control session */
67 +enum pptp_ctrlsess_state {
68 + PPTP_SESSION_NONE, /* no session present */
69 + PPTP_SESSION_ERROR, /* some session error */
70 + PPTP_SESSION_STOPREQ, /* stop_sess request seen */
71 + PPTP_SESSION_REQUESTED, /* start_sess request seen */
72 + PPTP_SESSION_CONFIRMED, /* session established */
73 +};
74 +
75 +/* state of the call inside the control session */
76 +enum pptp_ctrlcall_state {
77 + PPTP_CALL_NONE,
78 + PPTP_CALL_ERROR,
79 + PPTP_CALL_OUT_REQ,
80 + PPTP_CALL_OUT_CONF,
81 + PPTP_CALL_IN_REQ,
82 + PPTP_CALL_IN_REP,
83 + PPTP_CALL_IN_CONF,
84 + PPTP_CALL_CLEAR_REQ,
85 +};
86 +
87 +
88 +/* conntrack private data */
89 +struct ip_ct_pptp_master {
90 + enum pptp_ctrlsess_state sstate; /* session state */
91 +
92 + /* everything below is going to be per-expectation in newnat,
93 + * since there could be more than one call within one session */
94 + enum pptp_ctrlcall_state cstate; /* call state */
95 + u_int16_t pac_call_id; /* call id of PAC, host byte order */
96 + u_int16_t pns_call_id; /* call id of PNS, host byte order */
97 +};
98 +
99 +/* conntrack_expect private member */
100 +struct ip_ct_pptp_expect {
101 + enum pptp_ctrlcall_state cstate; /* call state */
102 + u_int16_t pac_call_id; /* call id of PAC */
103 + u_int16_t pns_call_id; /* call id of PNS */
104 +};
105 +
106 +
107 +#ifdef __KERNEL__
108 +
109 +#include <linux/netfilter_ipv4/lockhelp.h>
110 +DECLARE_LOCK_EXTERN(ip_pptp_lock);
111 +
112 +#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
113 +
114 +union pptp_ctrl_union {
115 + void *rawreq;
116 + struct PptpStartSessionRequest *sreq;
117 + struct PptpStartSessionReply *srep;
118 + struct PptpStopSessionRequest *streq;
119 + struct PptpStopSessionReply *strep;
120 + struct PptpOutCallRequest *ocreq;
121 + struct PptpOutCallReply *ocack;
122 + struct PptpInCallRequest *icreq;
123 + struct PptpInCallReply *icack;
124 + struct PptpInCallConnected *iccon;
125 + struct PptpClearCallRequest *clrreq;
126 + struct PptpCallDisconnectNotify *disc;
127 + struct PptpWanErrorNotify *wanerr;
128 + struct PptpSetLinkInfo *setlink;
129 +};
130 +
131 +
132 +
133 +#define PPTP_CONTROL_PORT 1723
134 +
135 +#define PPTP_PACKET_CONTROL 1
136 +#define PPTP_PACKET_MGMT 2
137 +
138 +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d
139 +
140 +struct pptp_pkt_hdr {
141 + __u16 packetLength;
142 + __u16 packetType;
143 + __u32 magicCookie;
144 +};
145 +
146 +/* PptpControlMessageType values */
147 +#define PPTP_START_SESSION_REQUEST 1
148 +#define PPTP_START_SESSION_REPLY 2
149 +#define PPTP_STOP_SESSION_REQUEST 3
150 +#define PPTP_STOP_SESSION_REPLY 4
151 +#define PPTP_ECHO_REQUEST 5
152 +#define PPTP_ECHO_REPLY 6
153 +#define PPTP_OUT_CALL_REQUEST 7
154 +#define PPTP_OUT_CALL_REPLY 8
155 +#define PPTP_IN_CALL_REQUEST 9
156 +#define PPTP_IN_CALL_REPLY 10
157 +#define PPTP_IN_CALL_CONNECT 11
158 +#define PPTP_CALL_CLEAR_REQUEST 12
159 +#define PPTP_CALL_DISCONNECT_NOTIFY 13
160 +#define PPTP_WAN_ERROR_NOTIFY 14
161 +#define PPTP_SET_LINK_INFO 15
162 +
163 +#define PPTP_MSG_MAX 15
164 +
165 +/* PptpGeneralError values */
166 +#define PPTP_ERROR_CODE_NONE 0
167 +#define PPTP_NOT_CONNECTED 1
168 +#define PPTP_BAD_FORMAT 2
169 +#define PPTP_BAD_VALUE 3
170 +#define PPTP_NO_RESOURCE 4
171 +#define PPTP_BAD_CALLID 5
172 +#define PPTP_REMOVE_DEVICE_ERROR 6
173 +
174 +struct PptpControlHeader {
175 + __u16 messageType;
176 + __u16 reserved;
177 +};
178 +
179 +/* FramingCapability Bitmap Values */
180 +#define PPTP_FRAME_CAP_ASYNC 0x1
181 +#define PPTP_FRAME_CAP_SYNC 0x2
182 +
183 +/* BearerCapability Bitmap Values */
184 +#define PPTP_BEARER_CAP_ANALOG 0x1
185 +#define PPTP_BEARER_CAP_DIGITAL 0x2
186 +
187 +struct PptpStartSessionRequest {
188 + __u16 protocolVersion;
189 + __u8 reserved1;
190 + __u8 reserved2;
191 + __u32 framingCapability;
192 + __u32 bearerCapability;
193 + __u16 maxChannels;
194 + __u16 firmwareRevision;
195 + __u8 hostName[64];
196 + __u8 vendorString[64];
197 +};
198 +
199 +/* PptpStartSessionResultCode Values */
200 +#define PPTP_START_OK 1
201 +#define PPTP_START_GENERAL_ERROR 2
202 +#define PPTP_START_ALREADY_CONNECTED 3
203 +#define PPTP_START_NOT_AUTHORIZED 4
204 +#define PPTP_START_UNKNOWN_PROTOCOL 5
205 +
206 +struct PptpStartSessionReply {
207 + __u16 protocolVersion;
208 + __u8 resultCode;
209 + __u8 generalErrorCode;
210 + __u32 framingCapability;
211 + __u32 bearerCapability;
212 + __u16 maxChannels;
213 + __u16 firmwareRevision;
214 + __u8 hostName[64];
215 + __u8 vendorString[64];
216 +};
217 +
218 +/* PptpStopReasons */
219 +#define PPTP_STOP_NONE 1
220 +#define PPTP_STOP_PROTOCOL 2
221 +#define PPTP_STOP_LOCAL_SHUTDOWN 3
222 +
223 +struct PptpStopSessionRequest {
224 + __u8 reason;
225 +};
226 +
227 +/* PptpStopSessionResultCode */
228 +#define PPTP_STOP_OK 1
229 +#define PPTP_STOP_GENERAL_ERROR 2
230 +
231 +struct PptpStopSessionReply {
232 + __u8 resultCode;
233 + __u8 generalErrorCode;
234 +};
235 +
236 +struct PptpEchoRequest {
237 + __u32 identNumber;
238 +};
239 +
240 +/* PptpEchoReplyResultCode */
241 +#define PPTP_ECHO_OK 1
242 +#define PPTP_ECHO_GENERAL_ERROR 2
243 +
244 +struct PptpEchoReply {
245 + __u32 identNumber;
246 + __u8 resultCode;
247 + __u8 generalErrorCode;
248 + __u16 reserved;
249 +};
250 +
251 +/* PptpFramingType */
252 +#define PPTP_ASYNC_FRAMING 1
253 +#define PPTP_SYNC_FRAMING 2
254 +#define PPTP_DONT_CARE_FRAMING 3
255 +
256 +/* PptpCallBearerType */
257 +#define PPTP_ANALOG_TYPE 1
258 +#define PPTP_DIGITAL_TYPE 2
259 +#define PPTP_DONT_CARE_BEARER_TYPE 3
260 +
261 +struct PptpOutCallRequest {
262 + __u16 callID;
263 + __u16 callSerialNumber;
264 + __u32 minBPS;
265 + __u32 maxBPS;
266 + __u32 bearerType;
267 + __u32 framingType;
268 + __u16 packetWindow;
269 + __u16 packetProcDelay;
270 + __u16 reserved1;
271 + __u16 phoneNumberLength;
272 + __u16 reserved2;
273 + __u8 phoneNumber[64];
274 + __u8 subAddress[64];
275 +};
276 +
277 +/* PptpCallResultCode */
278 +#define PPTP_OUTCALL_CONNECT 1
279 +#define PPTP_OUTCALL_GENERAL_ERROR 2
280 +#define PPTP_OUTCALL_NO_CARRIER 3
281 +#define PPTP_OUTCALL_BUSY 4
282 +#define PPTP_OUTCALL_NO_DIAL_TONE 5
283 +#define PPTP_OUTCALL_TIMEOUT 6
284 +#define PPTP_OUTCALL_DONT_ACCEPT 7
285 +
286 +struct PptpOutCallReply {
287 + __u16 callID;
288 + __u16 peersCallID;
289 + __u8 resultCode;
290 + __u8 generalErrorCode;
291 + __u16 causeCode;
292 + __u32 connectSpeed;
293 + __u16 packetWindow;
294 + __u16 packetProcDelay;
295 + __u32 physChannelID;
296 +};
297 +
298 +struct PptpInCallRequest {
299 + __u16 callID;
300 + __u16 callSerialNumber;
301 + __u32 callBearerType;
302 + __u32 physChannelID;
303 + __u16 dialedNumberLength;
304 + __u16 dialingNumberLength;
305 + __u8 dialedNumber[64];
306 + __u8 dialingNumber[64];
307 + __u8 subAddress[64];
308 +};
309 +
310 +/* PptpInCallResultCode */
311 +#define PPTP_INCALL_ACCEPT 1
312 +#define PPTP_INCALL_GENERAL_ERROR 2
313 +#define PPTP_INCALL_DONT_ACCEPT 3
314 +
315 +struct PptpInCallReply {
316 + __u16 callID;
317 + __u16 peersCallID;
318 + __u8 resultCode;
319 + __u8 generalErrorCode;
320 + __u16 packetWindow;
321 + __u16 packetProcDelay;
322 + __u16 reserved;
323 +};
324 +
325 +struct PptpInCallConnected {
326 + __u16 peersCallID;
327 + __u16 reserved;
328 + __u32 connectSpeed;
329 + __u16 packetWindow;
330 + __u16 packetProcDelay;
331 + __u32 callFramingType;
332 +};
333 +
334 +struct PptpClearCallRequest {
335 + __u16 callID;
336 + __u16 reserved;
337 +};
338 +
339 +struct PptpCallDisconnectNotify {
340 + __u16 callID;
341 + __u8 resultCode;
342 + __u8 generalErrorCode;
343 + __u16 causeCode;
344 + __u16 reserved;
345 + __u8 callStatistics[128];
346 +};
347 +
348 +struct PptpWanErrorNotify {
349 + __u16 peersCallID;
350 + __u16 reserved;
351 + __u32 crcErrors;
352 + __u32 framingErrors;
353 + __u32 hardwareOverRuns;
354 + __u32 bufferOverRuns;
355 + __u32 timeoutErrors;
356 + __u32 alignmentErrors;
357 +};
358 +
359 +struct PptpSetLinkInfo {
360 + __u16 peersCallID;
361 + __u16 reserved;
362 + __u32 sendAccm;
363 + __u32 recvAccm;
364 +};
365 +
366 +
367 +struct pptp_priv_data {
368 + __u16 call_id;
369 + __u16 mcall_id;
370 + __u16 pcall_id;
371 +};
372 +
373 +#endif /* __KERNEL__ */
374 +#endif /* _CONNTRACK_PPTP_H */
375 diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
376 --- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1970-01-01 01:00:00.000000000 +0100
377 +++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2005-04-02 19:10:45.000000000 +0200
378 @@ -0,0 +1,123 @@
379 +#ifndef _CONNTRACK_PROTO_GRE_H
380 +#define _CONNTRACK_PROTO_GRE_H
381 +#include <asm/byteorder.h>
382 +
383 +/* GRE PROTOCOL HEADER */
384 +
385 +/* GRE Version field */
386 +#define GRE_VERSION_1701 0x0
387 +#define GRE_VERSION_PPTP 0x1
388 +
389 +/* GRE Protocol field */
390 +#define GRE_PROTOCOL_PPTP 0x880B
391 +
392 +/* GRE Flags */
393 +#define GRE_FLAG_C 0x80
394 +#define GRE_FLAG_R 0x40
395 +#define GRE_FLAG_K 0x20
396 +#define GRE_FLAG_S 0x10
397 +#define GRE_FLAG_A 0x80
398 +
399 +#define GRE_IS_C(f) ((f)&GRE_FLAG_C)
400 +#define GRE_IS_R(f) ((f)&GRE_FLAG_R)
401 +#define GRE_IS_K(f) ((f)&GRE_FLAG_K)
402 +#define GRE_IS_S(f) ((f)&GRE_FLAG_S)
403 +#define GRE_IS_A(f) ((f)&GRE_FLAG_A)
404 +
405 +/* GRE is a mess: Four different standards */
406 +struct gre_hdr {
407 +#if defined(__LITTLE_ENDIAN_BITFIELD)
408 + __u16 rec:3,
409 + srr:1,
410 + seq:1,
411 + key:1,
412 + routing:1,
413 + csum:1,
414 + version:3,
415 + reserved:4,
416 + ack:1;
417 +#elif defined(__BIG_ENDIAN_BITFIELD)
418 + __u16 csum:1,
419 + routing:1,
420 + key:1,
421 + seq:1,
422 + srr:1,
423 + rec:3,
424 + ack:1,
425 + reserved:4,
426 + version:3;
427 +#else
428 +#error "Adjust your <asm/byteorder.h> defines"
429 +#endif
430 + __u16 protocol;
431 +};
432 +
433 +/* modified GRE header for PPTP */
434 +struct gre_hdr_pptp {
435 + __u8 flags; /* bitfield */
436 + __u8 version; /* should be GRE_VERSION_PPTP */
437 + __u16 protocol; /* should be GRE_PROTOCOL_PPTP */
438 + __u16 payload_len; /* size of ppp payload, not inc. gre header */
439 + __u16 call_id; /* peer's call_id for this session */
440 + __u32 seq; /* sequence number. Present if S==1 */
441 + __u32 ack; /* seq number of highest packet recieved by */
442 + /* sender in this session */
443 +};
444 +
445 +
446 +/* this is part of ip_conntrack */
447 +struct ip_ct_gre {
448 + unsigned int stream_timeout;
449 + unsigned int timeout;
450 +};
451 +
452 +/* this is part of ip_conntrack_expect */
453 +struct ip_ct_gre_expect {
454 + struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
455 +};
456 +
457 +#ifdef __KERNEL__
458 +struct ip_conntrack_expect;
459 +
460 +/* structure for original <-> reply keymap */
461 +struct ip_ct_gre_keymap {
462 + struct list_head list;
463 +
464 + struct ip_conntrack_tuple tuple;
465 +};
466 +
467 +
468 +/* add new tuple->key_reply pair to keymap */
469 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
470 + struct ip_conntrack_tuple *t,
471 + int reply);
472 +
473 +/* change an existing keymap entry */
474 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
475 + struct ip_conntrack_tuple *t);
476 +
477 +/* delete keymap entries */
478 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
479 +
480 +
481 +/* get pointer to gre key, if present */
482 +static inline u_int32_t *gre_key(struct gre_hdr *greh)
483 +{
484 + if (!greh->key)
485 + return NULL;
486 + if (greh->csum || greh->routing)
487 + return (u_int32_t *) (greh+sizeof(*greh)+4);
488 + return (u_int32_t *) (greh+sizeof(*greh));
489 +}
490 +
491 +/* get pointer ot gre csum, if present */
492 +static inline u_int16_t *gre_csum(struct gre_hdr *greh)
493 +{
494 + if (!greh->csum)
495 + return NULL;
496 + return (u_int16_t *) (greh+sizeof(*greh));
497 +}
498 +
499 +#endif /* __KERNEL__ */
500 +
501 +#endif /* _CONNTRACK_PROTO_GRE_H */
502 diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
503 --- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-11-28 19:26:21.000000000 +0100
504 +++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2005-04-02 19:07:18.000000000 +0200
505 @@ -14,7 +14,7 @@
506 union ip_conntrack_manip_proto
507 {
508 /* Add other protocols here. */
509 - u_int16_t all;
510 + u_int32_t all;
511
512 struct {
513 u_int16_t port;
514 @@ -25,6 +25,9 @@
515 struct {
516 u_int16_t id;
517 } icmp;
518 + struct {
519 + u_int32_t key;
520 + } gre;
521 };
522
523 /* The manipulable part of the tuple. */
524 @@ -44,7 +47,7 @@
525 u_int32_t ip;
526 union {
527 /* Add other protocols here. */
528 - u_int16_t all;
529 + u_int32_t all;
530
531 struct {
532 u_int16_t port;
533 @@ -55,6 +58,9 @@
534 struct {
535 u_int8_t type, code;
536 } icmp;
537 + struct {
538 + u_int32_t key;
539 + } gre;
540 } u;
541
542 /* The protocol. */
543 @@ -80,10 +86,16 @@
544 #ifdef __KERNEL__
545
546 #define DUMP_TUPLE(tp) \
547 -DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
548 +DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \
549 (tp), (tp)->dst.protonum, \
550 - NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
551 - NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
552 + NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \
553 + NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all))
554 +
555 +#define DUMP_TUPLE_RAW(x) \
556 + DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\
557 + (x), (x)->dst.protonum, \
558 + NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \
559 + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all))
560
561 #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
562
563 diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h
564 --- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h 1970-01-01 01:00:00.000000000 +0100
565 +++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h 2005-04-02 19:07:18.000000000 +0200
566 @@ -0,0 +1,11 @@
567 +/* PPTP constants and structs */
568 +#ifndef _NAT_PPTP_H
569 +#define _NAT_PPTP_H
570 +
571 +/* conntrack private data */
572 +struct ip_nat_pptp {
573 + u_int16_t pns_call_id; /* NAT'ed PNS call id */
574 + u_int16_t pac_call_id; /* NAT'ed PAC call id */
575 +};
576 +
577 +#endif /* _NAT_PPTP_H */
578 diff -urN linux-2.4.29-old/net/ipv4/netfilter/Config.in linux-2.4.29-dev/net/ipv4/netfilter/Config.in
579 --- linux-2.4.29-old/net/ipv4/netfilter/Config.in 2005-04-02 19:04:11.000000000 +0200
580 +++ linux-2.4.29-dev/net/ipv4/netfilter/Config.in 2005-04-02 19:07:18.000000000 +0200
581 @@ -10,6 +10,8 @@
582 dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
583 dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
584 dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
585 + dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
586 + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
587 fi
588
589 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
590 @@ -67,6 +69,20 @@
591 define_bool CONFIG_IP_NF_NAT_NEEDED y
592 dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
593 dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
594 + if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then
595 + define_tristate CONFIG_IP_NF_NAT_PPTP m
596 + else
597 + if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then
598 + define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT
599 + fi
600 + fi
601 + if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then
602 + define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m
603 + else
604 + if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then
605 + define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
606 + fi
607 + fi
608 if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then
609 define_tristate CONFIG_IP_NF_NAT_AMANDA m
610 else
611 diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c
612 --- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-02 19:04:11.000000000 +0200
613 +++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-02 19:07:18.000000000 +0200
614 @@ -142,6 +142,8 @@
615 tuple->dst.ip = iph->daddr;
616 tuple->dst.protonum = iph->protocol;
617
618 + tuple->src.u.all = tuple->dst.u.all = 0;
619 +
620 ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
621 len - 4*iph->ihl,
622 tuple);
623 @@ -157,6 +159,8 @@
624 inverse->dst.ip = orig->src.ip;
625 inverse->dst.protonum = orig->dst.protonum;
626
627 + inverse->src.u.all = inverse->dst.u.all = 0;
628 +
629 return protocol->invert_tuple(inverse, orig);
630 }
631
632 @@ -954,8 +958,8 @@
633 * so there is no need to use the tuple lock too */
634
635 DEBUGP("ip_conntrack_expect_related %p\n", related_to);
636 - DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
637 - DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
638 + DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
639 + DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask);
640
641 old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
642 struct ip_conntrack_expect *, &expect->tuple,
643 @@ -1072,15 +1076,14 @@
644
645 MUST_BE_READ_LOCKED(&ip_conntrack_lock);
646 WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
647 -
648 DEBUGP("change_expect:\n");
649 - DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
650 - DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
651 - DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
652 + DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
653 + DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask);
654 + DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple);
655 if (expect->ct_tuple.dst.protonum == 0) {
656 /* Never seen before */
657 DEBUGP("change expect: never seen before\n");
658 - if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
659 + if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
660 && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
661 struct ip_conntrack_expect *, newtuple, &expect->mask)) {
662 /* Force NAT to find an unused tuple */
663 diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
664 --- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1970-01-01 01:00:00.000000000 +0100
665 +++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2005-04-02 19:14:10.000000000 +0200
666 @@ -0,0 +1,24 @@
667 +#ifndef _IP_CT_PPTP_PRIV_H
668 +#define _IP_CT_PPTP_PRIV_H
669 +
670 +/* PptpControlMessageType names */
671 +static const char *strMName[] = {
672 + "UNKNOWN_MESSAGE",
673 + "START_SESSION_REQUEST",
674 + "START_SESSION_REPLY",
675 + "STOP_SESSION_REQUEST",
676 + "STOP_SESSION_REPLY",
677 + "ECHO_REQUEST",
678 + "ECHO_REPLY",
679 + "OUT_CALL_REQUEST",
680 + "OUT_CALL_REPLY",
681 + "IN_CALL_REQUEST",
682 + "IN_CALL_REPLY",
683 + "IN_CALL_CONNECT",
684 + "CALL_CLEAR_REQUEST",
685 + "CALL_DISCONNECT_NOTIFY",
686 + "WAN_ERROR_NOTIFY",
687 + "SET_LINK_INFO"
688 +};
689 +
690 +#endif
691 diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c
692 --- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
693 +++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2005-04-02 19:14:31.000000000 +0200
694 @@ -0,0 +1,333 @@
695 +/*
696 + * ip_conntrack_proto_gre.c - Version 1.2
697 + *
698 + * Connection tracking protocol helper module for GRE.
699 + *
700 + * GRE is a generic encapsulation protocol, which is generally not very
701 + * suited for NAT, as it has no protocol-specific part as port numbers.
702 + *
703 + * It has an optional key field, which may help us distinguishing two
704 + * connections between the same two hosts.
705 + *
706 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
707 + *
708 + * PPTP is built on top of a modified version of GRE, and has a mandatory
709 + * field called "CallID", which serves us for the same purpose as the key
710 + * field in plain GRE.
711 + *
712 + * Documentation about PPTP can be found in RFC 2637
713 + *
714 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
715 + *
716 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
717 + *
718 + */
719 +
720 +#include <linux/config.h>
721 +#include <linux/module.h>
722 +#include <linux/types.h>
723 +#include <linux/timer.h>
724 +#include <linux/netfilter.h>
725 +#include <linux/ip.h>
726 +#include <linux/in.h>
727 +#include <linux/list.h>
728 +
729 +#include <linux/netfilter_ipv4/lockhelp.h>
730 +
731 +DECLARE_RWLOCK(ip_ct_gre_lock);
732 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
733 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
734 +
735 +#include <linux/netfilter_ipv4/listhelp.h>
736 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
737 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
738 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
739 +
740 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
741 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
742 +
743 +MODULE_LICENSE("GPL");
744 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
745 +MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
746 +
747 +/* shamelessly stolen from ip_conntrack_proto_udp.c */
748 +#define GRE_TIMEOUT (30*HZ)
749 +#define GRE_STREAM_TIMEOUT (180*HZ)
750 +
751 +#if 0
752 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
753 + ": " format, ## args)
754 +#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
755 + NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
756 + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key))
757 +#else
758 +#define DEBUGP(x, args...)
759 +#define DUMP_TUPLE_GRE(x)
760 +#endif
761 +
762 +/* GRE KEYMAP HANDLING FUNCTIONS */
763 +static LIST_HEAD(gre_keymap_list);
764 +
765 +static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
766 + const struct ip_conntrack_tuple *t)
767 +{
768 + return ((km->tuple.src.ip == t->src.ip) &&
769 + (km->tuple.dst.ip == t->dst.ip) &&
770 + (km->tuple.dst.protonum == t->dst.protonum) &&
771 + (km->tuple.dst.u.all == t->dst.u.all));
772 +}
773 +
774 +/* look up the source key for a given tuple */
775 +static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
776 +{
777 + struct ip_ct_gre_keymap *km;
778 + u_int32_t key;
779 +
780 + READ_LOCK(&ip_ct_gre_lock);
781 + km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
782 + struct ip_ct_gre_keymap *, t);
783 + if (!km) {
784 + READ_UNLOCK(&ip_ct_gre_lock);
785 + return 0;
786 + }
787 +
788 + key = km->tuple.src.u.gre.key;
789 + READ_UNLOCK(&ip_ct_gre_lock);
790 +
791 + return key;
792 +}
793 +
794 +/* add a single keymap entry, associate with specified expect */
795 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
796 + struct ip_conntrack_tuple *t, int reply)
797 +{
798 + struct ip_ct_gre_keymap *km;
799 +
800 + km = kmalloc(sizeof(*km), GFP_ATOMIC);
801 + if (!km)
802 + return -1;
803 +
804 + /* initializing list head should be sufficient */
805 + memset(km, 0, sizeof(*km));
806 +
807 + memcpy(&km->tuple, t, sizeof(*t));
808 +
809 + if (!reply)
810 + exp->proto.gre.keymap_orig = km;
811 + else
812 + exp->proto.gre.keymap_reply = km;
813 +
814 + DEBUGP("adding new entry %p: ", km);
815 + DUMP_TUPLE_GRE(&km->tuple);
816 +
817 + WRITE_LOCK(&ip_ct_gre_lock);
818 + list_append(&gre_keymap_list, km);
819 + WRITE_UNLOCK(&ip_ct_gre_lock);
820 +
821 + return 0;
822 +}
823 +
824 +/* change the tuple of a keymap entry (used by nat helper) */
825 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
826 + struct ip_conntrack_tuple *t)
827 +{
828 + DEBUGP("changing entry %p to: ", km);
829 + DUMP_TUPLE_GRE(t);
830 +
831 + WRITE_LOCK(&ip_ct_gre_lock);
832 + memcpy(&km->tuple, t, sizeof(km->tuple));
833 + WRITE_UNLOCK(&ip_ct_gre_lock);
834 +}
835 +
836 +/* destroy the keymap entries associated with specified expect */
837 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
838 +{
839 + DEBUGP("entering for exp %p\n", exp);
840 + WRITE_LOCK(&ip_ct_gre_lock);
841 + if (exp->proto.gre.keymap_orig) {
842 + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
843 + list_del(&exp->proto.gre.keymap_orig->list);
844 + kfree(exp->proto.gre.keymap_orig);
845 + exp->proto.gre.keymap_orig = NULL;
846 + }
847 + if (exp->proto.gre.keymap_reply) {
848 + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
849 + list_del(&exp->proto.gre.keymap_reply->list);
850 + kfree(exp->proto.gre.keymap_reply);
851 + exp->proto.gre.keymap_reply = NULL;
852 + }
853 + WRITE_UNLOCK(&ip_ct_gre_lock);
854 +}
855 +
856 +
857 +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
858 +
859 +/* invert gre part of tuple */
860 +static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
861 + const struct ip_conntrack_tuple *orig)
862 +{
863 + tuple->dst.u.gre.key = orig->src.u.gre.key;
864 + tuple->src.u.gre.key = orig->dst.u.gre.key;
865 +
866 + return 1;
867 +}
868 +
869 +/* gre hdr info to tuple */
870 +static int gre_pkt_to_tuple(const void *datah, size_t datalen,
871 + struct ip_conntrack_tuple *tuple)
872 +{
873 + struct gre_hdr *grehdr = (struct gre_hdr *) datah;
874 + struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
875 + u_int32_t srckey;
876 +
877 + /* core guarantees 8 protocol bytes, no need for size check */
878 +
879 + switch (grehdr->version) {
880 + case GRE_VERSION_1701:
881 + if (!grehdr->key) {
882 + DEBUGP("Can't track GRE without key\n");
883 + return 0;
884 + }
885 + tuple->dst.u.gre.key = *(gre_key(grehdr));
886 + break;
887 +
888 + case GRE_VERSION_PPTP:
889 + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
890 + DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
891 + return 0;
892 + }
893 + tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
894 + break;
895 +
896 + default:
897 + printk(KERN_WARNING "unknown GRE version %hu\n",
898 + grehdr->version);
899 + return 0;
900 + }
901 +
902 + srckey = gre_keymap_lookup(tuple);
903 +
904 +#if 0
905 + DEBUGP("found src key %x for tuple ", ntohl(srckey));
906 + DUMP_TUPLE_GRE(tuple);
907 +#endif
908 + tuple->src.u.gre.key = srckey;
909 +
910 + return 1;
911 +}
912 +
913 +/* print gre part of tuple */
914 +static unsigned int gre_print_tuple(char *buffer,
915 + const struct ip_conntrack_tuple *tuple)
916 +{
917 + return sprintf(buffer, "srckey=0x%x dstkey=0x%x ",
918 + ntohl(tuple->src.u.gre.key),
919 + ntohl(tuple->dst.u.gre.key));
920 +}
921 +
922 +/* print private data for conntrack */
923 +static unsigned int gre_print_conntrack(char *buffer,
924 + const struct ip_conntrack *ct)
925 +{
926 + return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
927 + (ct->proto.gre.timeout / HZ),
928 + (ct->proto.gre.stream_timeout / HZ));
929 +}
930 +
931 +/* Returns verdict for packet, and may modify conntrack */
932 +static int gre_packet(struct ip_conntrack *ct,
933 + struct iphdr *iph, size_t len,
934 + enum ip_conntrack_info conntrackinfo)
935 +{
936 + /* If we've seen traffic both ways, this is a GRE connection.
937 + * Extend timeout. */
938 + if (ct->status & IPS_SEEN_REPLY) {
939 + ip_ct_refresh_acct(ct, ct->proto.gre.stream_timeout);
940 + /* Also, more likely to be important, and not a probe. */
941 + set_bit(IPS_ASSURED_BIT, &ct->status);
942 + } else
943 + ip_ct_refresh_acct(ct, ct->proto.gre.timeout);
944 +
945 + return NF_ACCEPT;
946 +}
947 +
948 +/* Called when a new connection for this protocol found. */
949 +static int gre_new(struct ip_conntrack *ct,
950 + struct iphdr *iph, size_t len)
951 +{
952 + DEBUGP(": ");
953 + DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
954 +
955 + /* initialize to sane value. Ideally a conntrack helper
956 + * (e.g. in case of pptp) is increasing them */
957 + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
958 + ct->proto.gre.timeout = GRE_TIMEOUT;
959 +
960 + return 1;
961 +}
962 +
963 +/* Called when a conntrack entry has already been removed from the hashes
964 + * and is about to be deleted from memory */
965 +static void gre_destroy(struct ip_conntrack *ct)
966 +{
967 + struct ip_conntrack_expect *master = ct->master;
968 +
969 + DEBUGP(" entering\n");
970 +
971 + if (!master) {
972 + DEBUGP("no master exp for ct %p\n", ct);
973 + return;
974 + }
975 +
976 + ip_ct_gre_keymap_destroy(master);
977 +}
978 +
979 +/* protocol helper struct */
980 +static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
981 + "gre",
982 + gre_pkt_to_tuple,
983 + gre_invert_tuple,
984 + gre_print_tuple,
985 + gre_print_conntrack,
986 + gre_packet,
987 + gre_new,
988 + gre_destroy,
989 + NULL,
990 + THIS_MODULE };
991 +
992 +/* ip_conntrack_proto_gre initialization */
993 +static int __init init(void)
994 +{
995 + int retcode;
996 +
997 + if ((retcode = ip_conntrack_protocol_register(&gre))) {
998 + printk(KERN_ERR "Unable to register conntrack protocol "
999 + "helper for gre: %d\n", retcode);
1000 + return -EIO;
1001 + }
1002 +
1003 + return 0;
1004 +}
1005 +
1006 +static void __exit fini(void)
1007 +{
1008 + struct list_head *pos, *n;
1009 +
1010 + /* delete all keymap entries */
1011 + WRITE_LOCK(&ip_ct_gre_lock);
1012 + list_for_each_safe(pos, n, &gre_keymap_list) {
1013 + DEBUGP("deleting keymap %p at module unload time\n", pos);
1014 + list_del(pos);
1015 + kfree(pos);
1016 + }
1017 + WRITE_UNLOCK(&ip_ct_gre_lock);
1018 +
1019 + ip_conntrack_protocol_unregister(&gre);
1020 +}
1021 +
1022 +EXPORT_SYMBOL(ip_ct_gre_keymap_add);
1023 +EXPORT_SYMBOL(ip_ct_gre_keymap_change);
1024 +EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
1025 +
1026 +module_init(init);
1027 +module_exit(fini);
1028 diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c
1029 --- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c 2005-01-19 15:10:13.000000000 +0100
1030 +++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c 2005-04-02 19:07:18.000000000 +0200
1031 @@ -424,7 +424,7 @@
1032 *tuple = *orig_tuple;
1033 while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
1034 != NULL) {
1035 - DEBUGP("Found best for "); DUMP_TUPLE(tuple);
1036 + DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple);
1037 /* 3) The per-protocol part of the manip is made to
1038 map into the range to make a unique tuple. */
1039
1040 @@ -564,9 +564,9 @@
1041 HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
1042 conntrack);
1043 DEBUGP("Original: ");
1044 - DUMP_TUPLE(&orig_tp);
1045 + DUMP_TUPLE_RAW(&orig_tp);
1046 DEBUGP("New: ");
1047 - DUMP_TUPLE(&new_tuple);
1048 + DUMP_TUPLE_RAW(&new_tuple);
1049 #endif
1050
1051 /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
1052 diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c
1053 --- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c 1970-01-01 01:00:00.000000000 +0100
1054 +++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c 2005-04-02 19:14:52.000000000 +0200
1055 @@ -0,0 +1,475 @@
1056 +/*
1057 + * ip_nat_pptp.c - Version 1.5
1058 + *
1059 + * NAT support for PPTP (Point to Point Tunneling Protocol).
1060 + * PPTP is a a protocol for creating virtual private networks.
1061 + * It is a specification defined by Microsoft and some vendors
1062 + * working with Microsoft. PPTP is built on top of a modified
1063 + * version of the Internet Generic Routing Encapsulation Protocol.
1064 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of
1065 + * PPTP can be found in RFC 2637
1066 + *
1067 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1068 + *
1069 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1070 + *
1071 + * TODO: - Support for multiple calls within one session
1072 + * (needs netfilter newnat code)
1073 + * - NAT to a unique tuple, not to TCP source port
1074 + * (needs netfilter tuple reservation)
1075 + *
1076 + * Changes:
1077 + * 2002-02-10 - Version 1.3
1078 + * - Use ip_nat_mangle_tcp_packet() because of cloned skb's
1079 + * in local connections (Philip Craig <philipc@snapgear.com>)
1080 + * - add checks for magicCookie and pptp version
1081 + * - make argument list of pptp_{out,in}bound_packet() shorter
1082 + * - move to C99 style initializers
1083 + * - print version number at module loadtime
1084 + * 2003-09-22 - Version 1.5
1085 + * - use SNATed tcp sourceport as callid, since we get called before
1086 + * TCP header is mangled (Philip Craig <philipc@snapgear.com>)
1087 + *
1088 + */
1089 +
1090 +#include <linux/config.h>
1091 +#include <linux/module.h>
1092 +#include <linux/ip.h>
1093 +#include <linux/tcp.h>
1094 +#include <net/tcp.h>
1095 +#include <linux/netfilter_ipv4/ip_nat.h>
1096 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
1097 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
1098 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
1099 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1100 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1101 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1102 +
1103 +#define IP_NAT_PPTP_VERSION "1.5"
1104 +
1105 +MODULE_LICENSE("GPL");
1106 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1107 +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
1108 +
1109 +
1110 +#if 0
1111 +#include "ip_conntrack_pptp_priv.h"
1112 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1113 + ": " format, ## args)
1114 +#else
1115 +#define DEBUGP(format, args...)
1116 +#endif
1117 +
1118 +static unsigned int
1119 +pptp_nat_expected(struct sk_buff **pskb,
1120 + unsigned int hooknum,
1121 + struct ip_conntrack *ct,
1122 + struct ip_nat_info *info)
1123 +{
1124 + struct ip_conntrack *master = master_ct(ct);
1125 + struct ip_nat_multi_range mr;
1126 + struct ip_ct_pptp_master *ct_pptp_info;
1127 + struct ip_nat_pptp *nat_pptp_info;
1128 + u_int32_t newip, newcid;
1129 + int ret;
1130 +
1131 + IP_NF_ASSERT(info);
1132 + IP_NF_ASSERT(master);
1133 + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
1134 +
1135 + DEBUGP("we have a connection!\n");
1136 +
1137 + LOCK_BH(&ip_pptp_lock);
1138 + ct_pptp_info = &master->help.ct_pptp_info;
1139 + nat_pptp_info = &master->nat.help.nat_pptp_info;
1140 +
1141 + /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
1142 + * (unmanipulated) values */
1143 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
1144 + DEBUGP("completing tuples with NAT info \n");
1145 + /* we can do this, since we're unconfirmed */
1146 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1147 + htonl(ct_pptp_info->pac_call_id)) {
1148 + /* assume PNS->PAC */
1149 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1150 + htonl(nat_pptp_info->pns_call_id);
1151 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1152 + htonl(nat_pptp_info->pns_call_id);
1153 + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
1154 + newcid = htonl(nat_pptp_info->pac_call_id);
1155 + } else {
1156 + /* assume PAC->PNS */
1157 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1158 + htonl(nat_pptp_info->pac_call_id);
1159 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1160 + htonl(nat_pptp_info->pac_call_id);
1161 + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1162 + newcid = htonl(nat_pptp_info->pns_call_id);
1163 + }
1164 + } else {
1165 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1166 + htonl(ct_pptp_info->pac_call_id)) {
1167 + /* assume PNS->PAC */
1168 + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1169 + newcid = htonl(ct_pptp_info->pns_call_id);
1170 + }
1171 + else {
1172 + /* assume PAC->PNS */
1173 + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
1174 + newcid = htonl(ct_pptp_info->pac_call_id);
1175 + }
1176 + }
1177 +
1178 + mr.rangesize = 1;
1179 + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
1180 + mr.range[0].min_ip = mr.range[0].max_ip = newip;
1181 + mr.range[0].min = mr.range[0].max =
1182 + ((union ip_conntrack_manip_proto ) { newcid });
1183 + DEBUGP("change ip to %u.%u.%u.%u\n",
1184 + NIPQUAD(newip));
1185 + DEBUGP("change key to 0x%x\n", ntohl(newcid));
1186 + ret = ip_nat_setup_info(ct, &mr, hooknum);
1187 +
1188 + UNLOCK_BH(&ip_pptp_lock);
1189 +
1190 + return ret;
1191 +
1192 +}
1193 +
1194 +/* outbound packets == from PNS to PAC */
1195 +static inline unsigned int
1196 +pptp_outbound_pkt(struct sk_buff **pskb,
1197 + struct ip_conntrack *ct,
1198 + enum ip_conntrack_info ctinfo,
1199 + struct ip_conntrack_expect *exp)
1200 +
1201 +{
1202 + struct iphdr *iph = (*pskb)->nh.iph;
1203 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1204 + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
1205 + ((void *)tcph + tcph->doff*4);
1206 +
1207 + struct PptpControlHeader *ctlh;
1208 + union pptp_ctrl_union pptpReq;
1209 + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
1210 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
1211 +
1212 + u_int16_t msg, *cid = NULL, new_callid;
1213 +
1214 + /* FIXME: size checks !!! */
1215 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
1216 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
1217 +
1218 + new_callid = htons(ct_pptp_info->pns_call_id);
1219 +
1220 + switch (msg = ntohs(ctlh->messageType)) {
1221 + case PPTP_OUT_CALL_REQUEST:
1222 + cid = &pptpReq.ocreq->callID;
1223 + /* FIXME: ideally we would want to reserve a call ID
1224 + * here. current netfilter NAT core is not able to do
1225 + * this :( For now we use TCP source port. This breaks
1226 + * multiple calls within one control session */
1227 +
1228 + /* save original call ID in nat_info */
1229 + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
1230 +
1231 + /* don't use tcph->source since we are at a DSTmanip
1232 + * hook (e.g. PREROUTING) and pkt is not mangled yet */
1233 + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
1234 +
1235 + /* save new call ID in ct info */
1236 + ct_pptp_info->pns_call_id = ntohs(new_callid);
1237 + break;
1238 + case PPTP_IN_CALL_REPLY:
1239 + cid = &pptpReq.icreq->callID;
1240 + break;
1241 + case PPTP_CALL_CLEAR_REQUEST:
1242 + cid = &pptpReq.clrreq->callID;
1243 + break;
1244 + default:
1245 + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
1246 + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
1247 + /* fall through */
1248 +
1249 + case PPTP_SET_LINK_INFO:
1250 + /* only need to NAT in case PAC is behind NAT box */
1251 + case PPTP_START_SESSION_REQUEST:
1252 + case PPTP_START_SESSION_REPLY:
1253 + case PPTP_STOP_SESSION_REQUEST:
1254 + case PPTP_STOP_SESSION_REPLY:
1255 + case PPTP_ECHO_REQUEST:
1256 + case PPTP_ECHO_REPLY:
1257 + /* no need to alter packet */
1258 + return NF_ACCEPT;
1259 + }
1260 +
1261 + IP_NF_ASSERT(cid);
1262 +
1263 + DEBUGP("altering call id from 0x%04x to 0x%04x\n",
1264 + ntohs(*cid), ntohs(new_callid));
1265 +
1266 + /* mangle packet */
1267 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
1268 + sizeof(new_callid), (char *)&new_callid,
1269 + sizeof(new_callid));
1270 +
1271 + return NF_ACCEPT;
1272 +}
1273 +
1274 +/* inbound packets == from PAC to PNS */
1275 +static inline unsigned int
1276 +pptp_inbound_pkt(struct sk_buff **pskb,
1277 + struct ip_conntrack *ct,
1278 + enum ip_conntrack_info ctinfo,
1279 + struct ip_conntrack_expect *oldexp)
1280 +{
1281 + struct iphdr *iph = (*pskb)->nh.iph;
1282 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1283 + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
1284 + ((void *)tcph + tcph->doff*4);
1285 +
1286 + struct PptpControlHeader *ctlh;
1287 + union pptp_ctrl_union pptpReq;
1288 + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
1289 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
1290 +
1291 + u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
1292 + u_int32_t old_dst_ip;
1293 +
1294 + struct ip_conntrack_tuple t, inv_t;
1295 + struct ip_conntrack_tuple *orig_t, *reply_t;
1296 +
1297 + /* FIXME: size checks !!! */
1298 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
1299 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
1300 +
1301 + new_pcid = htons(nat_pptp_info->pns_call_id);
1302 +
1303 + switch (msg = ntohs(ctlh->messageType)) {
1304 + case PPTP_OUT_CALL_REPLY:
1305 + pcid = &pptpReq.ocack->peersCallID;
1306 + cid = &pptpReq.ocack->callID;
1307 + if (!oldexp) {
1308 + DEBUGP("outcall but no expectation\n");
1309 + break;
1310 + }
1311 + old_dst_ip = oldexp->tuple.dst.ip;
1312 + t = oldexp->tuple;
1313 + invert_tuplepr(&inv_t, &t);
1314 +
1315 + /* save original PAC call ID in nat_info */
1316 + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
1317 +
1318 + /* alter expectation */
1319 + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
1320 + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
1321 + if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
1322 + /* expectation for PNS->PAC direction */
1323 + t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
1324 + t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
1325 + inv_t.src.ip = reply_t->src.ip;
1326 + inv_t.dst.ip = reply_t->dst.ip;
1327 + inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
1328 + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
1329 + } else {
1330 + /* expectation for PAC->PNS direction */
1331 + t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
1332 + t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
1333 + inv_t.src.ip = orig_t->src.ip;
1334 + inv_t.dst.ip = orig_t->dst.ip;
1335 + inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
1336 + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
1337 + }
1338 +
1339 + if (!ip_conntrack_change_expect(oldexp, &t)) {
1340 + DEBUGP("successfully changed expect\n");
1341 + } else {
1342 + DEBUGP("can't change expect\n");
1343 + }
1344 + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t);
1345 + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t);
1346 + break;
1347 + case PPTP_IN_CALL_CONNECT:
1348 + pcid = &pptpReq.iccon->peersCallID;
1349 + if (!oldexp)
1350 + break;
1351 + old_dst_ip = oldexp->tuple.dst.ip;
1352 + t = oldexp->tuple;
1353 +
1354 + /* alter expectation, no need for callID */
1355 + if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
1356 + /* expectation for PNS->PAC direction */
1357 + t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1358 + } else {
1359 + /* expectation for PAC->PNS direction */
1360 + t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1361 + }
1362 +
1363 + if (!ip_conntrack_change_expect(oldexp, &t)) {
1364 + DEBUGP("successfully changed expect\n");
1365 + } else {
1366 + DEBUGP("can't change expect\n");
1367 + }
1368 + break;
1369 + case PPTP_IN_CALL_REQUEST:
1370 + /* only need to nat in case PAC is behind NAT box */
1371 + break;
1372 + case PPTP_WAN_ERROR_NOTIFY:
1373 + pcid = &pptpReq.wanerr->peersCallID;
1374 + break;
1375 + case PPTP_CALL_DISCONNECT_NOTIFY:
1376 + pcid = &pptpReq.disc->callID;
1377 + break;
1378 +
1379 + default:
1380 + DEBUGP("unknown inbound packet %s\n",
1381 + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
1382 + /* fall through */
1383 +
1384 + case PPTP_START_SESSION_REQUEST:
1385 + case PPTP_START_SESSION_REPLY:
1386 + case PPTP_STOP_SESSION_REQUEST:
1387 + case PPTP_STOP_SESSION_REPLY:
1388 + case PPTP_ECHO_REQUEST:
1389 + case PPTP_ECHO_REPLY:
1390 + /* no need to alter packet */
1391 + return NF_ACCEPT;
1392 + }
1393 +
1394 + /* mangle packet */
1395 + IP_NF_ASSERT(pcid);
1396 + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
1397 + ntohs(*pcid), ntohs(new_pcid));
1398 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
1399 + sizeof(new_pcid), (char *)&new_pcid,
1400 + sizeof(new_pcid));
1401 +
1402 + if (new_cid) {
1403 + IP_NF_ASSERT(cid);
1404 + DEBUGP("altering call id from 0x%04x to 0x%04x\n",
1405 + ntohs(*cid), ntohs(new_cid));
1406 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
1407 + (void *)cid - (void *)pptph,
1408 + sizeof(new_cid), (char *)&new_cid,
1409 + sizeof(new_cid));
1410 + }
1411 +
1412 + /* great, at least we don't need to resize packets */
1413 + return NF_ACCEPT;
1414 +}
1415 +
1416 +
1417 +static unsigned int tcp_help(struct ip_conntrack *ct,
1418 + struct ip_conntrack_expect *exp,
1419 + struct ip_nat_info *info,
1420 + enum ip_conntrack_info ctinfo,
1421 + unsigned int hooknum, struct sk_buff **pskb)
1422 +{
1423 + struct iphdr *iph = (*pskb)->nh.iph;
1424 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1425 + unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
1426 + struct pptp_pkt_hdr *pptph;
1427 +
1428 + int dir;
1429 +
1430 + DEBUGP("entering\n");
1431 +
1432 + /* Only mangle things once: DST for original direction
1433 + and SRC for reply direction. */
1434 + dir = CTINFO2DIR(ctinfo);
1435 + if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
1436 + && dir == IP_CT_DIR_ORIGINAL)
1437 + || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
1438 + && dir == IP_CT_DIR_REPLY))) {
1439 + DEBUGP("Not touching dir %s at hook %s\n",
1440 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
1441 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
1442 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
1443 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
1444 + : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
1445 + return NF_ACCEPT;
1446 + }
1447 +
1448 + /* if packet is too small, just skip it */
1449 + if (datalen < sizeof(struct pptp_pkt_hdr)+
1450 + sizeof(struct PptpControlHeader)) {
1451 + DEBUGP("pptp packet too short\n");
1452 + return NF_ACCEPT;
1453 + }
1454 +
1455 + pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
1456 +
1457 + /* if it's not a control message, we can't handle it */
1458 + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
1459 + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
1460 + DEBUGP("not a pptp control packet\n");
1461 + return NF_ACCEPT;
1462 + }
1463 +
1464 + LOCK_BH(&ip_pptp_lock);
1465 +
1466 + if (dir == IP_CT_DIR_ORIGINAL) {
1467 + /* reuqests sent by client to server (PNS->PAC) */
1468 + pptp_outbound_pkt(pskb, ct, ctinfo, exp);
1469 + } else {
1470 + /* response from the server to the client (PAC->PNS) */
1471 + pptp_inbound_pkt(pskb, ct, ctinfo, exp);
1472 + }
1473 +
1474 + UNLOCK_BH(&ip_pptp_lock);
1475 +
1476 + return NF_ACCEPT;
1477 +}
1478 +
1479 +/* nat helper struct for control connection */
1480 +static struct ip_nat_helper pptp_tcp_helper = {
1481 + .list = { NULL, NULL },
1482 + .name = "pptp",
1483 + .flags = IP_NAT_HELPER_F_ALWAYS,
1484 + .me = THIS_MODULE,
1485 + .tuple = { .src = { .ip = 0,
1486 + .u = { .tcp = { .port =
1487 + __constant_htons(PPTP_CONTROL_PORT) }
1488 + }
1489 + },
1490 + .dst = { .ip = 0,
1491 + .u = { .all = 0 },
1492 + .protonum = IPPROTO_TCP
1493 + }
1494 + },
1495 +
1496 + .mask = { .src = { .ip = 0,
1497 + .u = { .tcp = { .port = 0xFFFF } }
1498 + },
1499 + .dst = { .ip = 0,
1500 + .u = { .all = 0 },
1501 + .protonum = 0xFFFF
1502 + }
1503 + },
1504 + .help = tcp_help,
1505 + .expect = pptp_nat_expected
1506 +};
1507 +
1508 +
1509 +static int __init init(void)
1510 +{
1511 + DEBUGP("%s: registering NAT helper\n", __FILE__);
1512 + if (ip_nat_helper_register(&pptp_tcp_helper)) {
1513 + printk(KERN_ERR "Unable to register NAT application helper "
1514 + "for pptp\n");
1515 + return -EIO;
1516 + }
1517 +
1518 + printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
1519 + return 0;
1520 +}
1521 +
1522 +static void __exit fini(void)
1523 +{
1524 + DEBUGP("cleanup_module\n" );
1525 + ip_nat_helper_unregister(&pptp_tcp_helper);
1526 + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
1527 +}
1528 +
1529 +module_init(init);
1530 +module_exit(fini);
1531 diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c
1532 --- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
1533 +++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c 2005-04-02 19:15:10.000000000 +0200
1534 @@ -0,0 +1,202 @@
1535 +/*
1536 + * ip_nat_proto_gre.c - Version 1.2
1537 + *
1538 + * NAT protocol helper module for GRE.
1539 + *
1540 + * GRE is a generic encapsulation protocol, which is generally not very
1541 + * suited for NAT, as it has no protocol-specific part as port numbers.
1542 + *
1543 + * It has an optional key field, which may help us distinguishing two
1544 + * connections between the same two hosts.
1545 + *
1546 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
1547 + *
1548 + * PPTP is built on top of a modified version of GRE, and has a mandatory
1549 + * field called "CallID", which serves us for the same purpose as the key
1550 + * field in plain GRE.
1551 + *
1552 + * Documentation about PPTP can be found in RFC 2637
1553 + *
1554 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1555 + *
1556 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1557 + *
1558 + */
1559 +
1560 +#include <linux/config.h>
1561 +#include <linux/module.h>
1562 +#include <linux/ip.h>
1563 +#include <linux/netfilter_ipv4/ip_nat.h>
1564 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
1565 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
1566 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1567 +
1568 +MODULE_LICENSE("GPL");
1569 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1570 +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
1571 +
1572 +#if 0
1573 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1574 + ": " format, ## args)
1575 +#else
1576 +#define DEBUGP(x, args...)
1577 +#endif
1578 +
1579 +/* is key in given range between min and max */
1580 +static int
1581 +gre_in_range(const struct ip_conntrack_tuple *tuple,
1582 + enum ip_nat_manip_type maniptype,
1583 + const union ip_conntrack_manip_proto *min,
1584 + const union ip_conntrack_manip_proto *max)
1585 +{
1586 + u_int32_t key;
1587 +
1588 + if (maniptype == IP_NAT_MANIP_SRC)
1589 + key = tuple->src.u.gre.key;
1590 + else
1591 + key = tuple->dst.u.gre.key;
1592 +
1593 + return ntohl(key) >= ntohl(min->gre.key)
1594 + && ntohl(key) <= ntohl(max->gre.key);
1595 +}
1596 +
1597 +/* generate unique tuple ... */
1598 +static int
1599 +gre_unique_tuple(struct ip_conntrack_tuple *tuple,
1600 + const struct ip_nat_range *range,
1601 + enum ip_nat_manip_type maniptype,
1602 + const struct ip_conntrack *conntrack)
1603 +{
1604 + u_int32_t min, i, range_size;
1605 + u_int32_t key = 0, *keyptr;
1606 +
1607 + if (maniptype == IP_NAT_MANIP_SRC)
1608 + keyptr = &tuple->src.u.gre.key;
1609 + else
1610 + keyptr = &tuple->dst.u.gre.key;
1611 +
1612 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
1613 +
1614 + DEBUGP("%p: NATing GRE PPTP\n", conntrack);
1615 + min = 1;
1616 + range_size = 0xffff;
1617 +
1618 + } else {
1619 + min = ntohl(range->min.gre.key);
1620 + range_size = ntohl(range->max.gre.key) - min + 1;
1621 + }
1622 +
1623 + DEBUGP("min = %u, range_size = %u\n", min, range_size);
1624 +
1625 + for (i = 0; i < range_size; i++, key++) {
1626 + *keyptr = htonl(min + key % range_size);
1627 + if (!ip_nat_used_tuple(tuple, conntrack))
1628 + return 1;
1629 + }
1630 +
1631 + DEBUGP("%p: no NAT mapping\n", conntrack);
1632 +
1633 + return 0;
1634 +}
1635 +
1636 +/* manipulate a GRE packet according to maniptype */
1637 +static void
1638 +gre_manip_pkt(struct iphdr *iph, size_t len,
1639 + const struct ip_conntrack_manip *manip,
1640 + enum ip_nat_manip_type maniptype)
1641 +{
1642 + struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
1643 + struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
1644 +
1645 + /* we only have destination manip of a packet, since 'source key'
1646 + * is not present in the packet itself */
1647 + if (maniptype == IP_NAT_MANIP_DST) {
1648 + /* key manipulation is always dest */
1649 + switch (greh->version) {
1650 + case 0:
1651 + if (!greh->key) {
1652 + DEBUGP("can't nat GRE w/o key\n");
1653 + break;
1654 + }
1655 + if (greh->csum) {
1656 + /* FIXME: Never tested this code... */
1657 + *(gre_csum(greh)) =
1658 + ip_nat_cheat_check(~*(gre_key(greh)),
1659 + manip->u.gre.key,
1660 + *(gre_csum(greh)));
1661 + }
1662 + *(gre_key(greh)) = manip->u.gre.key;
1663 + break;
1664 + case GRE_VERSION_PPTP:
1665 + DEBUGP("call_id -> 0x%04x\n",
1666 + ntohl(manip->u.gre.key));
1667 + pgreh->call_id = htons(ntohl(manip->u.gre.key));
1668 + break;
1669 + default:
1670 + DEBUGP("can't nat unknown GRE version\n");
1671 + break;
1672 + }
1673 + }
1674 +}
1675 +
1676 +/* print out a nat tuple */
1677 +static unsigned int
1678 +gre_print(char *buffer,
1679 + const struct ip_conntrack_tuple *match,
1680 + const struct ip_conntrack_tuple *mask)
1681 +{
1682 + unsigned int len = 0;
1683 +
1684 + if (mask->src.u.gre.key)
1685 + len += sprintf(buffer + len, "srckey=0x%x ",
1686 + ntohl(match->src.u.gre.key));
1687 +
1688 + if (mask->dst.u.gre.key)
1689 + len += sprintf(buffer + len, "dstkey=0x%x ",
1690 + ntohl(match->src.u.gre.key));
1691 +
1692 + return len;
1693 +}
1694 +
1695 +/* print a range of keys */
1696 +static unsigned int
1697 +gre_print_range(char *buffer, const struct ip_nat_range *range)
1698 +{
1699 + if (range->min.gre.key != 0
1700 + || range->max.gre.key != 0xFFFF) {
1701 + if (range->min.gre.key == range->max.gre.key)
1702 + return sprintf(buffer, "key 0x%x ",
1703 + ntohl(range->min.gre.key));
1704 + else
1705 + return sprintf(buffer, "keys 0x%u-0x%u ",
1706 + ntohl(range->min.gre.key),
1707 + ntohl(range->max.gre.key));
1708 + } else
1709 + return 0;
1710 +}
1711 +
1712 +/* nat helper struct */
1713 +static struct ip_nat_protocol gre =
1714 + { { NULL, NULL }, "GRE", IPPROTO_GRE,
1715 + gre_manip_pkt,
1716 + gre_in_range,
1717 + gre_unique_tuple,
1718 + gre_print,
1719 + gre_print_range
1720 + };
1721 +
1722 +static int __init init(void)
1723 +{
1724 + if (ip_nat_protocol_register(&gre))
1725 + return -EIO;
1726 +
1727 + return 0;
1728 +}
1729 +
1730 +static void __exit fini(void)
1731 +{
1732 + ip_nat_protocol_unregister(&gre);
1733 +}
1734 +
1735 +module_init(init);
1736 +module_exit(fini);
1737 diff -urN linux-2.4.29-old/net/ipv4/netfilter/Makefile linux-2.4.29-dev/net/ipv4/netfilter/Makefile
1738 --- linux-2.4.29-old/net/ipv4/netfilter/Makefile 2005-04-02 19:04:11.000000000 +0200
1739 +++ linux-2.4.29-dev/net/ipv4/netfilter/Makefile 2005-04-02 19:07:18.000000000 +0200
1740 @@ -36,23 +36,32 @@
1741 ifdef CONFIG_IP_NF_AMANDA
1742 export-objs += ip_conntrack_amanda.o
1743 endif
1744 -
1745 obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
1746 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
1747 ifdef CONFIG_IP_NF_FTP
1748 export-objs += ip_conntrack_ftp.o
1749 endif
1750 -
1751 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
1752 ifdef CONFIG_IP_NF_IRC
1753 export-objs += ip_conntrack_irc.o
1754 endif
1755 +obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
1756 +ifdef CONFIG_IP_NF_CT_PROTO_GRE
1757 + export-objs += ip_conntrack_proto_gre.o
1758 +endif
1759 +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
1760 +ifdef CONFIG_IP_NF_NAT_PPTP
1761 + export-objs += ip_conntrack_pptp.o
1762 +endif
1763 +
1764
1765 # NAT helpers
1766 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
1767 obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
1768 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
1769 obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
1770 +obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
1771 +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
1772
1773 # generic IP tables
1774 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
1775 --- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100
1776 +++ /home/florian//openwrt/trunk/openwrt/build_mipsel/linux/net/ipv4/netfilter/ip_conntrack_pptp.c 2006-02-04 18:23:27.000000000 +0100
1777 @@ -0,0 +1,635 @@
1778 +/*
1779 + * ip_conntrack_pptp.c - Version 1.9
1780 + *
1781 + * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
1782 + * PPTP is a a protocol for creating virtual private networks.
1783 + * It is a specification defined by Microsoft and some vendors
1784 + * working with Microsoft. PPTP is built on top of a modified
1785 + * version of the Internet Generic Routing Encapsulation Protocol.
1786 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of
1787 + * PPTP can be found in RFC 2637
1788 + *
1789 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1790 + *
1791 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1792 + *
1793 + * Limitations:
1794 + * - We blindly assume that control connections are always
1795 + * established in PNS->PAC direction. This is a violation
1796 + * of RFFC2673
1797 + *
1798 + * TODO: - finish support for multiple calls within one session
1799 + * (needs expect reservations in newnat)
1800 + * - testing of incoming PPTP calls
1801 + *
1802 + * Changes:
1803 + * 2002-02-05 - Version 1.3
1804 + * - Call ip_conntrack_unexpect_related() from
1805 + * pptp_timeout_related() to destroy expectations in case
1806 + * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
1807 + * (Philip Craig <philipc@snapgear.com>)
1808 + * - Add Version information at module loadtime
1809 + * 2002-02-10 - Version 1.6
1810 + * - move to C99 style initializers
1811 + * - remove second expectation if first arrives
1812 + *
1813 + */
1814 +
1815 +#include <linux/config.h>
1816 +#include <linux/module.h>
1817 +#include <linux/netfilter.h>
1818 +#include <linux/ip.h>
1819 +#include <net/checksum.h>
1820 +#include <net/tcp.h>
1821 +
1822 +#include <linux/netfilter_ipv4/lockhelp.h>
1823 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1824 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1825 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1826 +
1827 +#define IP_CT_PPTP_VERSION "1.9"
1828 +
1829 +MODULE_LICENSE("GPL");
1830 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1831 +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
1832 +
1833 +DECLARE_LOCK(ip_pptp_lock);
1834 +
1835 +#if 0
1836 +#include "ip_conntrack_pptp_priv.h"
1837 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1838 + ": " format, ## args)
1839 +#else
1840 +#define DEBUGP(format, args...)
1841 +#endif
1842 +
1843 +#define SECS *HZ
1844 +#define MINS * 60 SECS
1845 +#define HOURS * 60 MINS
1846 +#define DAYS * 24 HOURS
1847 +
1848 +#define PPTP_GRE_TIMEOUT (10 MINS)
1849 +#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS)
1850 +
1851 +static int pptp_expectfn(struct ip_conntrack *ct)
1852 +{
1853 + struct ip_conntrack *master;
1854 + struct ip_conntrack_expect *exp;
1855 +
1856 + DEBUGP("increasing timeouts\n");
1857 + /* increase timeout of GRE data channel conntrack entry */
1858 + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
1859 + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
1860 +
1861 + master = master_ct(ct);
1862 + if (!master) {
1863 + DEBUGP(" no master!!!\n");
1864 + return 0;
1865 + }
1866 +
1867 + exp = ct->master;
1868 + if (!exp) {
1869 + DEBUGP("no expectation!!\n");
1870 + return 0;
1871 + }
1872 +
1873 + DEBUGP("completing tuples with ct info\n");
1874 + /* we can do this, since we're unconfirmed */
1875 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1876 + htonl(master->help.ct_pptp_info.pac_call_id)) {
1877 + /* assume PNS->PAC */
1878 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1879 + htonl(master->help.ct_pptp_info.pns_call_id);
1880 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1881 + htonl(master->help.ct_pptp_info.pns_call_id);
1882 + } else {
1883 + /* assume PAC->PNS */
1884 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1885 + htonl(master->help.ct_pptp_info.pac_call_id);
1886 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1887 + htonl(master->help.ct_pptp_info.pac_call_id);
1888 + }
1889 +
1890 + /* delete other expectation */
1891 + if (exp->expected_list.next != &exp->expected_list) {
1892 + struct ip_conntrack_expect *other_exp;
1893 + struct list_head *cur_item, *next;
1894 +
1895 + for (cur_item = master->sibling_list.next;
1896 + cur_item != &master->sibling_list; cur_item = next) {
1897 + next = cur_item->next;
1898 + other_exp = list_entry(cur_item,
1899 + struct ip_conntrack_expect,
1900 + expected_list);
1901 + /* remove only if occurred at same sequence number */
1902 + if (other_exp != exp && other_exp->seq == exp->seq) {
1903 + DEBUGP("unexpecting other direction\n");
1904 + ip_ct_gre_keymap_destroy(other_exp);
1905 + ip_conntrack_unexpect_related(other_exp);
1906 + }
1907 + }
1908 + }
1909 +
1910 + return 0;
1911 +}
1912 +
1913 +/* timeout GRE data connections */
1914 +static int pptp_timeout_related(struct ip_conntrack *ct)
1915 +{
1916 + struct list_head *cur_item, *next;
1917 + struct ip_conntrack_expect *exp;
1918 + enum ip_conntrack_info ctinfo;
1919 + struct iphdr *iph;
1920 +
1921 + /* FIXME: do we have to lock something ? */
1922 + for (cur_item = ct->sibling_list.next;
1923 + cur_item != &ct->sibling_list; cur_item = next) {
1924 + next = cur_item->next;
1925 + exp = list_entry(cur_item, struct ip_conntrack_expect,
1926 + expected_list);
1927 +
1928 + ip_ct_gre_keymap_destroy(exp);
1929 + if (!exp->sibling) {
1930 + ip_conntrack_unexpect_related(exp);
1931 + continue;
1932 + }
1933 +
1934 + DEBUGP("setting timeout of conntrack %p to 0\n",
1935 + exp->sibling);
1936 + exp->sibling->proto.gre.timeout = 0;
1937 + exp->sibling->proto.gre.stream_timeout = 0;
1938 + ip_ct_refresh_acct(exp->sibling, ctinfo, iph, 0);
1939 + }
1940 +
1941 + return 0;
1942 +}
1943 +
1944 +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
1945 +static inline int
1946 +exp_gre(struct ip_conntrack *master,
1947 + u_int32_t seq,
1948 + u_int16_t callid,
1949 + u_int16_t peer_callid)
1950 +{
1951 + struct ip_conntrack_expect exp;
1952 + struct ip_conntrack_tuple inv_tuple;
1953 +
1954 + memset(&exp, 0, sizeof(exp));
1955 + /* tuple in original direction, PNS->PAC */
1956 + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1957 + exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
1958 + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
1959 + exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
1960 + exp.tuple.dst.protonum = IPPROTO_GRE;
1961 +
1962 + exp.mask.src.ip = 0xffffffff;
1963 + exp.mask.src.u.all = 0;
1964 + exp.mask.dst.u.all = 0;
1965 + exp.mask.dst.u.gre.key = 0xffffffff;
1966 + exp.mask.dst.ip = 0xffffffff;
1967 + exp.mask.dst.protonum = 0xffff;
1968 +
1969 + exp.seq = seq;
1970 + exp.expectfn = pptp_expectfn;
1971 +
1972 + exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
1973 + exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
1974 +
1975 + DEBUGP("calling expect_related ");
1976 + DUMP_TUPLE_RAW(&exp.tuple);
1977 +
1978 + /* Add GRE keymap entries */
1979 + if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
1980 + return 1;
1981 +
1982 + invert_tuplepr(&inv_tuple, &exp.tuple);
1983 + if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
1984 + ip_ct_gre_keymap_destroy(&exp);
1985 + return 1;
1986 + }
1987 +
1988 + if (ip_conntrack_expect_related(master, &exp) != 0) {
1989 + ip_ct_gre_keymap_destroy(&exp);
1990 + DEBUGP("cannot expect_related()\n");
1991 + return 1;
1992 + }
1993 +
1994 + /* tuple in reply direction, PAC->PNS */
1995 + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
1996 + exp.tuple.src.u.gre.key = htonl(ntohs(callid));
1997 + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1998 + exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
1999 +
2000 + DEBUGP("calling expect_related ");
2001 + DUMP_TUPLE_RAW(&exp.tuple);
2002 +
2003 + /* Add GRE keymap entries */
2004 + ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
2005 + invert_tuplepr(&inv_tuple, &exp.tuple);
2006 + ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
2007 + /* FIXME: cannot handle error correctly, since we need to free
2008 + * the above keymap :( */
2009 +
2010 + if (ip_conntrack_expect_related(master, &exp) != 0) {
2011 + /* free the second pair of keypmaps */
2012 + ip_ct_gre_keymap_destroy(&exp);
2013 + DEBUGP("cannot expect_related():\n");
2014 + return 1;
2015 + }
2016 +
2017 + return 0;
2018 +}
2019 +
2020 +static inline int
2021 +pptp_inbound_pkt(struct tcphdr *tcph,
2022 + struct pptp_pkt_hdr *pptph,
2023 + size_t datalen,
2024 + struct ip_conntrack *ct,
2025 + enum ip_conntrack_info ctinfo)
2026 +{
2027 + struct PptpControlHeader *ctlh;
2028 + union pptp_ctrl_union pptpReq;
2029 +
2030 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2031 + u_int16_t msg, *cid, *pcid;
2032 + u_int32_t seq;
2033 +
2034 + ctlh = (struct PptpControlHeader *)
2035 + ((char *) pptph + sizeof(struct pptp_pkt_hdr));
2036 + pptpReq.rawreq = (void *)
2037 + ((char *) ctlh + sizeof(struct PptpControlHeader));
2038 +
2039 + msg = ntohs(ctlh->messageType);
2040 + DEBUGP("inbound control message %s\n", strMName[msg]);
2041 +
2042 + switch (msg) {
2043 + case PPTP_START_SESSION_REPLY:
2044 + /* server confirms new control session */
2045 + if (info->sstate < PPTP_SESSION_REQUESTED) {
2046 + DEBUGP("%s without START_SESS_REQUEST\n",
2047 + strMName[msg]);
2048 + break;
2049 + }
2050 + if (pptpReq.srep->resultCode == PPTP_START_OK)
2051 + info->sstate = PPTP_SESSION_CONFIRMED;
2052 + else
2053 + info->sstate = PPTP_SESSION_ERROR;
2054 + break;
2055 +
2056 + case PPTP_STOP_SESSION_REPLY:
2057 + /* server confirms end of control session */
2058 + if (info->sstate > PPTP_SESSION_STOPREQ) {
2059 + DEBUGP("%s without STOP_SESS_REQUEST\n",
2060 + strMName[msg]);
2061 + break;
2062 + }
2063 + if (pptpReq.strep->resultCode == PPTP_STOP_OK)
2064 + info->sstate = PPTP_SESSION_NONE;
2065 + else
2066 + info->sstate = PPTP_SESSION_ERROR;
2067 + break;
2068 +
2069 + case PPTP_OUT_CALL_REPLY:
2070 + /* server accepted call, we now expect GRE frames */
2071 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2072 + DEBUGP("%s but no session\n", strMName[msg]);
2073 + break;
2074 + }
2075 + if (info->cstate != PPTP_CALL_OUT_REQ &&
2076 + info->cstate != PPTP_CALL_OUT_CONF) {
2077 + DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
2078 + break;
2079 + }
2080 + if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
2081 + info->cstate = PPTP_CALL_NONE;
2082 + break;
2083 + }
2084 +
2085 + cid = &pptpReq.ocack->callID;
2086 + pcid = &pptpReq.ocack->peersCallID;
2087 +
2088 + info->pac_call_id = ntohs(*cid);
2089 +
2090 + if (htons(info->pns_call_id) != *pcid) {
2091 + DEBUGP("%s for unknown callid %u\n",
2092 + strMName[msg], ntohs(*pcid));
2093 + break;
2094 + }
2095 +
2096 + DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
2097 + ntohs(*cid), ntohs(*pcid));
2098 +
2099 + info->cstate = PPTP_CALL_OUT_CONF;
2100 +
2101 + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2102 + if (exp_gre(ct, seq, *cid, *pcid) != 0)
2103 + printk("ip_conntrack_pptp: error during exp_gre\n");
2104 + break;
2105 +
2106 + case PPTP_IN_CALL_REQUEST:
2107 + /* server tells us about incoming call request */
2108 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2109 + DEBUGP("%s but no session\n", strMName[msg]);
2110 + break;
2111 + }
2112 + pcid = &pptpReq.icack->peersCallID;
2113 + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2114 + info->cstate = PPTP_CALL_IN_REQ;
2115 + info->pac_call_id= ntohs(*pcid);
2116 + break;
2117 +
2118 + case PPTP_IN_CALL_CONNECT:
2119 + /* server tells us about incoming call established */
2120 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2121 + DEBUGP("%s but no session\n", strMName[msg]);
2122 + break;
2123 + }
2124 + if (info->sstate != PPTP_CALL_IN_REP
2125 + && info->sstate != PPTP_CALL_IN_CONF) {
2126 + DEBUGP("%s but never sent IN_CALL_REPLY\n",
2127 + strMName[msg]);
2128 + break;
2129 + }
2130 +
2131 + pcid = &pptpReq.iccon->peersCallID;
2132 + cid = &info->pac_call_id;
2133 +
2134 + if (info->pns_call_id != ntohs(*pcid)) {
2135 + DEBUGP("%s for unknown CallID %u\n",
2136 + strMName[msg], ntohs(*cid));
2137 + break;
2138 + }
2139 +
2140 + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2141 + info->cstate = PPTP_CALL_IN_CONF;
2142 +
2143 + /* we expect a GRE connection from PAC to PNS */
2144 + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2145 + if (exp_gre(ct, seq, *cid, *pcid) != 0)
2146 + printk("ip_conntrack_pptp: error during exp_gre\n");
2147 +
2148 + break;
2149 +
2150 + case PPTP_CALL_DISCONNECT_NOTIFY:
2151 + /* server confirms disconnect */
2152 + cid = &pptpReq.disc->callID;
2153 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2154 + info->cstate = PPTP_CALL_NONE;
2155 +
2156 + /* untrack this call id, unexpect GRE packets */
2157 + pptp_timeout_related(ct);
2158 + break;
2159 +
2160 + case PPTP_WAN_ERROR_NOTIFY:
2161 + break;
2162 +
2163 + case PPTP_ECHO_REQUEST:
2164 + case PPTP_ECHO_REPLY:
2165 + /* I don't have to explain these ;) */
2166 + break;
2167 + default:
2168 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
2169 + ? strMName[msg]:strMName[0], msg);
2170 + break;
2171 + }
2172 +
2173 + return NF_ACCEPT;
2174 +
2175 +}
2176 +
2177 +static inline int
2178 +pptp_outbound_pkt(struct tcphdr *tcph,
2179 + struct pptp_pkt_hdr *pptph,
2180 + size_t datalen,
2181 + struct ip_conntrack *ct,
2182 + enum ip_conntrack_info ctinfo)
2183 +{
2184 + struct PptpControlHeader *ctlh;
2185 + union pptp_ctrl_union pptpReq;
2186 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2187 + u_int16_t msg, *cid, *pcid;
2188 +
2189 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
2190 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
2191 +
2192 + msg = ntohs(ctlh->messageType);
2193 + DEBUGP("outbound control message %s\n", strMName[msg]);
2194 +
2195 + switch (msg) {
2196 + case PPTP_START_SESSION_REQUEST:
2197 + /* client requests for new control session */
2198 + if (info->sstate != PPTP_SESSION_NONE) {
2199 + DEBUGP("%s but we already have one",
2200 + strMName[msg]);
2201 + }
2202 + info->sstate = PPTP_SESSION_REQUESTED;
2203 + break;
2204 + case PPTP_STOP_SESSION_REQUEST:
2205 + /* client requests end of control session */
2206 + info->sstate = PPTP_SESSION_STOPREQ;
2207 + break;
2208 +
2209 + case PPTP_OUT_CALL_REQUEST:
2210 + /* client initiating connection to server */
2211 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2212 + DEBUGP("%s but no session\n",
2213 + strMName[msg]);
2214 + break;
2215 + }
2216 + info->cstate = PPTP_CALL_OUT_REQ;
2217 + /* track PNS call id */
2218 + cid = &pptpReq.ocreq->callID;
2219 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2220 + info->pns_call_id = ntohs(*cid);
2221 + break;
2222 + case PPTP_IN_CALL_REPLY:
2223 + /* client answers incoming call */
2224 + if (info->cstate != PPTP_CALL_IN_REQ
2225 + && info->cstate != PPTP_CALL_IN_REP) {
2226 + DEBUGP("%s without incall_req\n",
2227 + strMName[msg]);
2228 + break;
2229 + }
2230 + if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
2231 + info->cstate = PPTP_CALL_NONE;
2232 + break;
2233 + }
2234 + pcid = &pptpReq.icack->peersCallID;
2235 + if (info->pac_call_id != ntohs(*pcid)) {
2236 + DEBUGP("%s for unknown call %u\n",
2237 + strMName[msg], ntohs(*pcid));
2238 + break;
2239 + }
2240 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
2241 + /* part two of the three-way handshake */
2242 + info->cstate = PPTP_CALL_IN_REP;
2243 + info->pns_call_id = ntohs(pptpReq.icack->callID);
2244 + break;
2245 +
2246 + case PPTP_CALL_CLEAR_REQUEST:
2247 + /* client requests hangup of call */
2248 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2249 + DEBUGP("CLEAR_CALL but no session\n");
2250 + break;
2251 + }
2252 + /* FUTURE: iterate over all calls and check if
2253 + * call ID is valid. We don't do this without newnat,
2254 + * because we only know about last call */
2255 + info->cstate = PPTP_CALL_CLEAR_REQ;
2256 + break;
2257 + case PPTP_SET_LINK_INFO:
2258 + break;
2259 + case PPTP_ECHO_REQUEST:
2260 + case PPTP_ECHO_REPLY:
2261 + /* I don't have to explain these ;) */
2262 + break;
2263 + default:
2264 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
2265 + strMName[msg]:strMName[0], msg);
2266 + /* unknown: no need to create GRE masq table entry */
2267 + break;
2268 + }
2269 +
2270 + return NF_ACCEPT;
2271 +}
2272 +
2273 +
2274 +/* track caller id inside control connection, call expect_related */
2275 +static int
2276 +conntrack_pptp_help(const struct iphdr *iph, size_t len,
2277 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
2278 +
2279 +{
2280 + struct pptp_pkt_hdr *pptph;
2281 +
2282 + struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
2283 + u_int32_t tcplen = len - iph->ihl * 4;
2284 + u_int32_t datalen = tcplen - tcph->doff * 4;
2285 + void *datalimit;
2286 + int dir = CTINFO2DIR(ctinfo);
2287 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2288 +
2289 + int oldsstate, oldcstate;
2290 + int ret;
2291 +
2292 + /* don't do any tracking before tcp handshake complete */
2293 + if (ctinfo != IP_CT_ESTABLISHED
2294 + && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
2295 + DEBUGP("ctinfo = %u, skipping\n", ctinfo);
2296 + return NF_ACCEPT;
2297 + }
2298 +
2299 + /* not a complete TCP header? */
2300 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
2301 + DEBUGP("tcplen = %u\n", tcplen);
2302 + return NF_ACCEPT;
2303 + }
2304 +
2305 + /* checksum invalid? */
2306 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
2307 + csum_partial((char *) tcph, tcplen, 0))) {
2308 + printk(KERN_NOTICE __FILE__ ": bad csum\n");
2309 + /* W2K PPTP server sends TCP packets with wrong checksum :(( */
2310 + //return NF_ACCEPT;
2311 + }
2312 +
2313 + if (tcph->fin || tcph->rst) {
2314 + DEBUGP("RST/FIN received, timeouting GRE\n");
2315 + /* can't do this after real newnat */
2316 + info->cstate = PPTP_CALL_NONE;
2317 +
2318 + /* untrack this call id, unexpect GRE packets */
2319 + pptp_timeout_related(ct);
2320 + }
2321 +
2322 +
2323 + pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
2324 + datalimit = (void *) pptph + datalen;
2325 +
2326 + /* not a full pptp packet header? */
2327 + if ((void *) pptph+sizeof(*pptph) >= datalimit) {
2328 + DEBUGP("no full PPTP header, can't track\n");
2329 + return NF_ACCEPT;
2330 + }
2331 +
2332 + /* if it's not a control message we can't do anything with it */
2333 + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
2334 + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
2335 + DEBUGP("not a control packet\n");
2336 + return NF_ACCEPT;
2337 + }
2338 +
2339 + oldsstate = info->sstate;
2340 + oldcstate = info->cstate;
2341 +
2342 + LOCK_BH(&ip_pptp_lock);
2343 +
2344 + /* FIXME: We just blindly assume that the control connection is always
2345 + * established from PNS->PAC. However, RFC makes no guarantee */
2346 + if (dir == IP_CT_DIR_ORIGINAL)
2347 + /* client -> server (PNS -> PAC) */
2348 + ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2349 + else
2350 + /* server -> client (PAC -> PNS) */
2351 + ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2352 + DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
2353 + oldsstate, info->sstate, oldcstate, info->cstate);
2354 + UNLOCK_BH(&ip_pptp_lock);
2355 +
2356 + return ret;
2357 +}
2358 +
2359 +/* control protocol helper */
2360 +static struct ip_conntrack_helper pptp = {
2361 + .list = { NULL, NULL },
2362 + .name = "pptp",
2363 + .flags = IP_CT_HELPER_F_REUSE_EXPECT,
2364 + .me = THIS_MODULE,
2365 + .max_expected = 2,
2366 + .timeout = 0,
2367 + .tuple = { .src = { .ip = 0,
2368 + .u = { .tcp = { .port =
2369 + __constant_htons(PPTP_CONTROL_PORT) } }
2370 + },
2371 + .dst = { .ip = 0,
2372 + .u = { .all = 0 },
2373 + .protonum = IPPROTO_TCP
2374 + }
2375 + },
2376 + .mask = { .src = { .ip = 0,
2377 + .u = { .tcp = { .port = 0xffff } }
2378 + },
2379 + .dst = { .ip = 0,
2380 + .u = { .all = 0 },
2381 + .protonum = 0xffff
2382 + }
2383 + },
2384 + .help = conntrack_pptp_help
2385 +};
2386 +
2387 +/* ip_conntrack_pptp initialization */
2388 +static int __init init(void)
2389 +{
2390 + int retcode;
2391 +
2392 + DEBUGP(__FILE__ ": registering helper\n");
2393 + if ((retcode = ip_conntrack_helper_register(&pptp))) {
2394 + printk(KERN_ERR "Unable to register conntrack application "
2395 + "helper for pptp: %d\n", retcode);
2396 + return -EIO;
2397 + }
2398 +
2399 + printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
2400 + return 0;
2401 +}
2402 +
2403 +static void __exit fini(void)
2404 +{
2405 + ip_conntrack_helper_unregister(&pptp);
2406 + printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
2407 +}
2408 +
2409 +module_init(init);
2410 +module_exit(fini);
2411 +
2412 +EXPORT_SYMBOL(ip_pptp_lock);