fix pptp nat commit - committed the wrong file
[openwrt.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,482 @@
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 +               if (oldexp->proto.gre.keymap_orig)
1345 +                       ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, 
1346 +                                               &t);
1347 +               if (oldexp->proto.gre.keymap_reply)
1348 +                       ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, 
1349 +                                               &inv_t);
1350 +               break;
1351 +       case PPTP_IN_CALL_CONNECT:
1352 +               pcid = &pptpReq.iccon->peersCallID;
1353 +               if (!oldexp)
1354 +                       break;
1355 +               old_dst_ip = oldexp->tuple.dst.ip;
1356 +               t = oldexp->tuple;
1357 +
1358 +               /* alter expectation, no need for callID */
1359 +               if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
1360 +                       /* expectation for PNS->PAC direction */
1361 +                       t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1362 +               } else {
1363 +                       /* expectation for PAC->PNS direction */
1364 +                       t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1365 +               }
1366 +
1367 +               if (!ip_conntrack_change_expect(oldexp, &t)) {
1368 +                       DEBUGP("successfully changed expect\n");
1369 +               } else {
1370 +                       DEBUGP("can't change expect\n");
1371 +               }
1372 +               break;
1373 +       case PPTP_IN_CALL_REQUEST:
1374 +               /* only need to nat in case PAC is behind NAT box */
1375 +               break;
1376 +       case PPTP_WAN_ERROR_NOTIFY:
1377 +               pcid = &pptpReq.wanerr->peersCallID;
1378 +               break;
1379 +       case PPTP_CALL_DISCONNECT_NOTIFY:
1380 +               pcid = &pptpReq.disc->callID;
1381 +               break;
1382 +       case PPTP_SET_LINK_INFO:
1383 +               pcid = &pptpReq.setlink->peersCallID;
1384 +               break;
1385 +
1386 +       default:
1387 +               DEBUGP("unknown inbound packet %s\n",
1388 +                       (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
1389 +               /* fall through */
1390 +
1391 +       case PPTP_START_SESSION_REQUEST:
1392 +       case PPTP_START_SESSION_REPLY:
1393 +       case PPTP_STOP_SESSION_REQUEST:
1394 +       case PPTP_STOP_SESSION_REPLY:
1395 +       case PPTP_ECHO_REQUEST:
1396 +       case PPTP_ECHO_REPLY:
1397 +               /* no need to alter packet */
1398 +               return NF_ACCEPT;
1399 +       }
1400 +
1401 +       /* mangle packet */
1402 +       IP_NF_ASSERT(pcid);
1403 +       DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
1404 +               ntohs(*pcid), ntohs(new_pcid));
1405 +       ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
1406 +                                sizeof(new_pcid), (char *)&new_pcid, 
1407 +                                sizeof(new_pcid));
1408 +
1409 +       if (new_cid) {
1410 +               IP_NF_ASSERT(cid);
1411 +               DEBUGP("altering call id from 0x%04x to 0x%04x\n",
1412 +                       ntohs(*cid), ntohs(new_cid));
1413 +               ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
1414 +                                        (void *)cid - (void *)pptph, 
1415 +                                        sizeof(new_cid), (char *)&new_cid, 
1416 +                                        sizeof(new_cid));
1417 +       }
1418 +
1419 +       /* great, at least we don't need to resize packets */
1420 +       return NF_ACCEPT;
1421 +}
1422 +
1423 +
1424 +static unsigned int tcp_help(struct ip_conntrack *ct,
1425 +                            struct ip_conntrack_expect *exp,
1426 +                            struct ip_nat_info *info,
1427 +                            enum ip_conntrack_info ctinfo,
1428 +                            unsigned int hooknum, struct sk_buff **pskb)
1429 +{
1430 +       struct iphdr *iph = (*pskb)->nh.iph;
1431 +       struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1432 +       unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
1433 +       struct pptp_pkt_hdr *pptph;
1434 +
1435 +       int dir;
1436 +
1437 +       DEBUGP("entering\n");
1438 +
1439 +       /* Only mangle things once: DST for original direction
1440 +          and SRC for reply direction. */
1441 +       dir = CTINFO2DIR(ctinfo);
1442 +       if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
1443 +            && dir == IP_CT_DIR_ORIGINAL)
1444 +             || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
1445 +                 && dir == IP_CT_DIR_REPLY))) {
1446 +               DEBUGP("Not touching dir %s at hook %s\n",
1447 +                      dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
1448 +                      hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
1449 +                      : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
1450 +                      : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
1451 +                      : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
1452 +               return NF_ACCEPT;
1453 +       }
1454 +
1455 +       /* if packet is too small, just skip it */
1456 +       if (datalen < sizeof(struct pptp_pkt_hdr)+
1457 +                     sizeof(struct PptpControlHeader)) {
1458 +               DEBUGP("pptp packet too short\n");
1459 +               return NF_ACCEPT;       
1460 +       }
1461 +
1462 +       pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
1463 +
1464 +       /* if it's not a control message, we can't handle it */
1465 +       if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
1466 +           ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
1467 +               DEBUGP("not a pptp control packet\n");
1468 +               return NF_ACCEPT;
1469 +       }
1470 +
1471 +       LOCK_BH(&ip_pptp_lock);
1472 +
1473 +       if (dir == IP_CT_DIR_ORIGINAL) {
1474 +               /* reuqests sent by client to server (PNS->PAC) */
1475 +               pptp_outbound_pkt(pskb, ct, ctinfo, exp);
1476 +       } else {
1477 +               /* response from the server to the client (PAC->PNS) */
1478 +               pptp_inbound_pkt(pskb, ct, ctinfo, exp);
1479 +       }
1480 +
1481 +       UNLOCK_BH(&ip_pptp_lock);
1482 +
1483 +       return NF_ACCEPT;
1484 +}
1485 +
1486 +/* nat helper struct for control connection */
1487 +static struct ip_nat_helper pptp_tcp_helper = { 
1488 +       .list = { NULL, NULL },
1489 +       .name = "pptp", 
1490 +       .flags = IP_NAT_HELPER_F_ALWAYS, 
1491 +       .me = THIS_MODULE,
1492 +       .tuple = { .src = { .ip = 0, 
1493 +                           .u = { .tcp = { .port = 
1494 +                                       __constant_htons(PPTP_CONTROL_PORT) } 
1495 +                                } 
1496 +                         },
1497 +                  .dst = { .ip = 0, 
1498 +                           .u = { .all = 0 }, 
1499 +                           .protonum = IPPROTO_TCP 
1500 +                         } 
1501 +                },
1502 +
1503 +       .mask = { .src = { .ip = 0, 
1504 +                          .u = { .tcp = { .port = 0xFFFF } } 
1505 +                        },
1506 +                 .dst = { .ip = 0, 
1507 +                          .u = { .all = 0 }, 
1508 +                          .protonum = 0xFFFF 
1509 +                        } 
1510 +               },
1511 +       .help = tcp_help, 
1512 +       .expect = pptp_nat_expected 
1513 +};
1514 +
1515 +                         
1516 +static int __init init(void)
1517 +{
1518 +       DEBUGP("%s: registering NAT helper\n", __FILE__);
1519 +       if (ip_nat_helper_register(&pptp_tcp_helper)) {
1520 +               printk(KERN_ERR "Unable to register NAT application helper "
1521 +                               "for pptp\n");
1522 +               return -EIO;
1523 +       }
1524 +
1525 +       printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
1526 +       return 0;
1527 +}
1528 +
1529 +static void __exit fini(void)
1530 +{
1531 +       DEBUGP("cleanup_module\n" );
1532 +       ip_nat_helper_unregister(&pptp_tcp_helper);
1533 +       printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
1534 +}
1535 +
1536 +module_init(init);
1537 +module_exit(fini);
1538 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
1539 --- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c      1970-01-01 01:00:00.000000000 +0100
1540 +++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c      2005-04-02 19:15:10.000000000 +0200
1541 @@ -0,0 +1,202 @@
1542 +/*
1543 + * ip_nat_proto_gre.c - Version 1.2
1544 + *
1545 + * NAT protocol helper module for GRE.
1546 + *
1547 + * GRE is a generic encapsulation protocol, which is generally not very
1548 + * suited for NAT, as it has no protocol-specific part as port numbers.
1549 + *
1550 + * It has an optional key field, which may help us distinguishing two 
1551 + * connections between the same two hosts.
1552 + *
1553 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 
1554 + *
1555 + * PPTP is built on top of a modified version of GRE, and has a mandatory
1556 + * field called "CallID", which serves us for the same purpose as the key
1557 + * field in plain GRE.
1558 + *
1559 + * Documentation about PPTP can be found in RFC 2637
1560 + *
1561 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1562 + *
1563 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1564 + *
1565 + */
1566 +
1567 +#include <linux/config.h>
1568 +#include <linux/module.h>
1569 +#include <linux/ip.h>
1570 +#include <linux/netfilter_ipv4/ip_nat.h>
1571 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
1572 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
1573 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1574 +
1575 +MODULE_LICENSE("GPL");
1576 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1577 +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
1578 +
1579 +#if 0
1580 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1581 +                                      ": " format, ## args)
1582 +#else
1583 +#define DEBUGP(x, args...)
1584 +#endif
1585 +
1586 +/* is key in given range between min and max */
1587 +static int
1588 +gre_in_range(const struct ip_conntrack_tuple *tuple,
1589 +            enum ip_nat_manip_type maniptype,
1590 +            const union ip_conntrack_manip_proto *min,
1591 +            const union ip_conntrack_manip_proto *max)
1592 +{
1593 +       u_int32_t key;
1594 +
1595 +       if (maniptype == IP_NAT_MANIP_SRC)
1596 +               key = tuple->src.u.gre.key;
1597 +       else
1598 +               key = tuple->dst.u.gre.key;
1599 +
1600 +       return ntohl(key) >= ntohl(min->gre.key)
1601 +               && ntohl(key) <= ntohl(max->gre.key);
1602 +}
1603 +
1604 +/* generate unique tuple ... */
1605 +static int 
1606 +gre_unique_tuple(struct ip_conntrack_tuple *tuple,
1607 +                const struct ip_nat_range *range,
1608 +                enum ip_nat_manip_type maniptype,
1609 +                const struct ip_conntrack *conntrack)
1610 +{
1611 +       u_int32_t min, i, range_size;
1612 +       u_int32_t key = 0, *keyptr;
1613 +
1614 +       if (maniptype == IP_NAT_MANIP_SRC)
1615 +               keyptr = &tuple->src.u.gre.key;
1616 +       else
1617 +               keyptr = &tuple->dst.u.gre.key;
1618 +
1619 +       if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
1620 +
1621 +               DEBUGP("%p: NATing GRE PPTP\n", conntrack);
1622 +               min = 1;
1623 +               range_size = 0xffff;
1624 +
1625 +       } else {
1626 +               min = ntohl(range->min.gre.key);
1627 +               range_size = ntohl(range->max.gre.key) - min + 1;
1628 +       }
1629 +
1630 +       DEBUGP("min = %u, range_size = %u\n", min, range_size); 
1631 +
1632 +       for (i = 0; i < range_size; i++, key++) {
1633 +               *keyptr = htonl(min + key % range_size);
1634 +               if (!ip_nat_used_tuple(tuple, conntrack))
1635 +                       return 1;
1636 +       }
1637 +
1638 +       DEBUGP("%p: no NAT mapping\n", conntrack);
1639 +
1640 +       return 0;
1641 +}
1642 +
1643 +/* manipulate a GRE packet according to maniptype */
1644 +static void 
1645 +gre_manip_pkt(struct iphdr *iph, size_t len, 
1646 +             const struct ip_conntrack_manip *manip,
1647 +             enum ip_nat_manip_type maniptype)
1648 +{
1649 +       struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
1650 +       struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
1651 +
1652 +       /* we only have destination manip of a packet, since 'source key' 
1653 +        * is not present in the packet itself */
1654 +       if (maniptype == IP_NAT_MANIP_DST) {
1655 +               /* key manipulation is always dest */
1656 +               switch (greh->version) {
1657 +               case 0:
1658 +                       if (!greh->key) {
1659 +                               DEBUGP("can't nat GRE w/o key\n");
1660 +                               break;
1661 +                       }
1662 +                       if (greh->csum) {
1663 +                               /* FIXME: Never tested this code... */
1664 +                               *(gre_csum(greh)) = 
1665 +                                       ip_nat_cheat_check(~*(gre_key(greh)),
1666 +                                                       manip->u.gre.key,
1667 +                                                       *(gre_csum(greh)));
1668 +                       }
1669 +                       *(gre_key(greh)) = manip->u.gre.key;
1670 +                       break;
1671 +               case GRE_VERSION_PPTP:
1672 +                       DEBUGP("call_id -> 0x%04x\n", 
1673 +                               ntohl(manip->u.gre.key));
1674 +                       pgreh->call_id = htons(ntohl(manip->u.gre.key));
1675 +                       break;
1676 +               default:
1677 +                       DEBUGP("can't nat unknown GRE version\n");
1678 +                       break;
1679 +               }
1680 +       }
1681 +}
1682 +
1683 +/* print out a nat tuple */
1684 +static unsigned int 
1685 +gre_print(char *buffer, 
1686 +         const struct ip_conntrack_tuple *match,
1687 +         const struct ip_conntrack_tuple *mask)
1688 +{
1689 +       unsigned int len = 0;
1690 +
1691 +       if (mask->src.u.gre.key)
1692 +               len += sprintf(buffer + len, "srckey=0x%x ", 
1693 +                               ntohl(match->src.u.gre.key));
1694 +
1695 +       if (mask->dst.u.gre.key)
1696 +               len += sprintf(buffer + len, "dstkey=0x%x ",
1697 +                               ntohl(match->src.u.gre.key));
1698 +
1699 +       return len;
1700 +}
1701 +
1702 +/* print a range of keys */
1703 +static unsigned int 
1704 +gre_print_range(char *buffer, const struct ip_nat_range *range)
1705 +{
1706 +       if (range->min.gre.key != 0 
1707 +           || range->max.gre.key != 0xFFFF) {
1708 +               if (range->min.gre.key == range->max.gre.key)
1709 +                       return sprintf(buffer, "key 0x%x ",
1710 +                                       ntohl(range->min.gre.key));
1711 +               else
1712 +                       return sprintf(buffer, "keys 0x%u-0x%u ",
1713 +                                       ntohl(range->min.gre.key),
1714 +                                       ntohl(range->max.gre.key));
1715 +       } else
1716 +               return 0;
1717 +}
1718 +
1719 +/* nat helper struct */
1720 +static struct ip_nat_protocol gre = 
1721 +       { { NULL, NULL }, "GRE", IPPROTO_GRE,
1722 +         gre_manip_pkt,
1723 +         gre_in_range,
1724 +         gre_unique_tuple,
1725 +         gre_print,
1726 +         gre_print_range 
1727 +       };
1728 +                                 
1729 +static int __init init(void)
1730 +{
1731 +        if (ip_nat_protocol_register(&gre))
1732 +                return -EIO;
1733 +
1734 +        return 0;
1735 +}
1736 +
1737 +static void __exit fini(void)
1738 +{
1739 +        ip_nat_protocol_unregister(&gre);
1740 +}
1741 +
1742 +module_init(init);
1743 +module_exit(fini);
1744 diff -urN linux-2.4.29-old/net/ipv4/netfilter/Makefile linux-2.4.29-dev/net/ipv4/netfilter/Makefile
1745 --- linux-2.4.29-old/net/ipv4/netfilter/Makefile        2005-04-02 19:04:11.000000000 +0200
1746 +++ linux-2.4.29-dev/net/ipv4/netfilter/Makefile        2005-04-02 19:07:18.000000000 +0200
1747 @@ -36,23 +36,32 @@
1748  ifdef CONFIG_IP_NF_AMANDA
1749         export-objs += ip_conntrack_amanda.o
1750  endif
1751 -
1752  obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
1753  obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
1754  ifdef CONFIG_IP_NF_FTP
1755         export-objs += ip_conntrack_ftp.o
1756  endif
1757 -
1758  obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
1759  ifdef CONFIG_IP_NF_IRC
1760         export-objs += ip_conntrack_irc.o
1761  endif
1762 +obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
1763 +ifdef CONFIG_IP_NF_CT_PROTO_GRE
1764 +       export-objs += ip_conntrack_proto_gre.o
1765 +endif
1766 +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
1767 +ifdef CONFIG_IP_NF_NAT_PPTP
1768 +       export-objs += ip_conntrack_pptp.o
1769 +endif
1770 +
1771  
1772  # NAT helpers 
1773  obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
1774  obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
1775  obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
1776  obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
1777 +obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
1778 +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
1779  
1780  # generic IP tables 
1781  obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
1782 --- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100
1783 +++ /home/florian//openwrt/trunk/openwrt/build_mipsel/linux/net/ipv4/netfilter/ip_conntrack_pptp.c      2006-02-04 18:23:27.000000000 +0100
1784 @@ -0,0 +1,635 @@
1785 +/*
1786 + * ip_conntrack_pptp.c - Version 1.9
1787 + *
1788 + * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
1789 + * PPTP is a a protocol for creating virtual private networks.
1790 + * It is a specification defined by Microsoft and some vendors
1791 + * working with Microsoft.  PPTP is built on top of a modified
1792 + * version of the Internet Generic Routing Encapsulation Protocol.
1793 + * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
1794 + * PPTP can be found in RFC 2637
1795 + *
1796 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1797 + *
1798 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1799 + *
1800 + * Limitations:
1801 + *      - We blindly assume that control connections are always
1802 + *        established in PNS->PAC direction.  This is a violation
1803 + *        of RFFC2673
1804 + *
1805 + * TODO: - finish support for multiple calls within one session
1806 + *        (needs expect reservations in newnat)
1807 + *      - testing of incoming PPTP calls 
1808 + *
1809 + * Changes: 
1810 + *     2002-02-05 - Version 1.3
1811 + *       - Call ip_conntrack_unexpect_related() from 
1812 + *         pptp_timeout_related() to destroy expectations in case
1813 + *         CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
1814 + *         (Philip Craig <philipc@snapgear.com>)
1815 + *       - Add Version information at module loadtime
1816 + *     2002-02-10 - Version 1.6
1817 + *       - move to C99 style initializers
1818 + *       - remove second expectation if first arrives
1819 + *
1820 + */
1821 +
1822 +#include <linux/config.h>
1823 +#include <linux/module.h>
1824 +#include <linux/netfilter.h>
1825 +#include <linux/ip.h>
1826 +#include <net/checksum.h>
1827 +#include <net/tcp.h>
1828 +
1829 +#include <linux/netfilter_ipv4/lockhelp.h>
1830 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1831 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1832 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1833 +
1834 +#define IP_CT_PPTP_VERSION "1.9"
1835 +
1836 +MODULE_LICENSE("GPL");
1837 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1838 +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
1839 +
1840 +DECLARE_LOCK(ip_pptp_lock);
1841 +
1842 +#if 0
1843 +#include "ip_conntrack_pptp_priv.h"
1844 +#define DEBUGP(format, args...)        printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1845 +                                       ": " format, ## args)
1846 +#else
1847 +#define DEBUGP(format, args...)
1848 +#endif
1849 +
1850 +#define SECS *HZ
1851 +#define MINS * 60 SECS
1852 +#define HOURS * 60 MINS
1853 +#define DAYS * 24 HOURS
1854 +
1855 +#define PPTP_GRE_TIMEOUT               (10 MINS)
1856 +#define PPTP_GRE_STREAM_TIMEOUT        (5 DAYS)
1857 +
1858 +static int pptp_expectfn(struct ip_conntrack *ct)
1859 +{
1860 +       struct ip_conntrack *master;
1861 +       struct ip_conntrack_expect *exp;
1862 +
1863 +       DEBUGP("increasing timeouts\n");
1864 +       /* increase timeout of GRE data channel conntrack entry */
1865 +       ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
1866 +       ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
1867 +
1868 +       master = master_ct(ct);
1869 +       if (!master) {
1870 +               DEBUGP(" no master!!!\n");
1871 +               return 0;
1872 +       }
1873 +
1874 +       exp = ct->master;
1875 +       if (!exp) {
1876 +               DEBUGP("no expectation!!\n");
1877 +               return 0;
1878 +       }
1879 +
1880 +       DEBUGP("completing tuples with ct info\n");
1881 +       /* we can do this, since we're unconfirmed */
1882 +       if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == 
1883 +               htonl(master->help.ct_pptp_info.pac_call_id)) { 
1884 +               /* assume PNS->PAC */
1885 +               ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = 
1886 +                       htonl(master->help.ct_pptp_info.pns_call_id);
1887 +               ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1888 +                       htonl(master->help.ct_pptp_info.pns_call_id);
1889 +       } else {
1890 +               /* assume PAC->PNS */
1891 +               ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1892 +                       htonl(master->help.ct_pptp_info.pac_call_id);
1893 +               ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1894 +                       htonl(master->help.ct_pptp_info.pac_call_id);
1895 +       }
1896 +       
1897 +       /* delete other expectation */
1898 +       if (exp->expected_list.next != &exp->expected_list) {
1899 +               struct ip_conntrack_expect *other_exp;
1900 +               struct list_head *cur_item, *next;
1901 +
1902 +               for (cur_item = master->sibling_list.next;
1903 +                    cur_item != &master->sibling_list; cur_item = next) {
1904 +                       next = cur_item->next;
1905 +                       other_exp = list_entry(cur_item,
1906 +                                              struct ip_conntrack_expect,
1907 +                                              expected_list);
1908 +                       /* remove only if occurred at same sequence number */
1909 +                       if (other_exp != exp && other_exp->seq == exp->seq) {
1910 +                               DEBUGP("unexpecting other direction\n");
1911 +                               ip_ct_gre_keymap_destroy(other_exp);
1912 +                               ip_conntrack_unexpect_related(other_exp);
1913 +                       }
1914 +               }
1915 +       }
1916 +
1917 +       return 0;
1918 +}
1919 +
1920 +/* timeout GRE data connections */
1921 +static int pptp_timeout_related(struct ip_conntrack *ct)
1922 +{
1923 +       struct list_head *cur_item, *next;
1924 +       struct ip_conntrack_expect *exp;
1925 +       enum ip_conntrack_info ctinfo;
1926 +       struct iphdr *iph;
1927 +
1928 +       /* FIXME: do we have to lock something ? */
1929 +       for (cur_item = ct->sibling_list.next;
1930 +           cur_item != &ct->sibling_list; cur_item = next) {
1931 +               next = cur_item->next;
1932 +               exp = list_entry(cur_item, struct ip_conntrack_expect,
1933 +                                expected_list);
1934 +
1935 +               ip_ct_gre_keymap_destroy(exp);
1936 +               if (!exp->sibling) {
1937 +                       ip_conntrack_unexpect_related(exp);
1938 +                       continue;
1939 +               }
1940 +
1941 +               DEBUGP("setting timeout of conntrack %p to 0\n",
1942 +                       exp->sibling);
1943 +               exp->sibling->proto.gre.timeout = 0;
1944 +               exp->sibling->proto.gre.stream_timeout = 0;
1945 +               ip_ct_refresh_acct(exp->sibling, ctinfo, iph, 0);
1946 +       }
1947 +
1948 +       return 0;
1949 +}
1950 +
1951 +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
1952 +static inline int
1953 +exp_gre(struct ip_conntrack *master,
1954 +       u_int32_t seq,
1955 +       u_int16_t callid,
1956 +       u_int16_t peer_callid)
1957 +{
1958 +       struct ip_conntrack_expect exp;
1959 +       struct ip_conntrack_tuple inv_tuple;
1960 +
1961 +       memset(&exp, 0, sizeof(exp));
1962 +       /* tuple in original direction, PNS->PAC */
1963 +       exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1964 +       exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
1965 +       exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
1966 +       exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
1967 +       exp.tuple.dst.protonum = IPPROTO_GRE;
1968 +
1969 +       exp.mask.src.ip = 0xffffffff;
1970 +       exp.mask.src.u.all = 0;
1971 +       exp.mask.dst.u.all = 0;
1972 +       exp.mask.dst.u.gre.key = 0xffffffff;
1973 +       exp.mask.dst.ip = 0xffffffff;
1974 +       exp.mask.dst.protonum = 0xffff;
1975 +                       
1976 +       exp.seq = seq;
1977 +       exp.expectfn = pptp_expectfn;
1978 +
1979 +       exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
1980 +       exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
1981 +
1982 +       DEBUGP("calling expect_related ");
1983 +       DUMP_TUPLE_RAW(&exp.tuple);
1984 +       
1985 +       /* Add GRE keymap entries */
1986 +       if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
1987 +               return 1;
1988 +
1989 +       invert_tuplepr(&inv_tuple, &exp.tuple);
1990 +       if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
1991 +               ip_ct_gre_keymap_destroy(&exp);
1992 +               return 1;
1993 +       }
1994 +       
1995 +       if (ip_conntrack_expect_related(master, &exp) != 0) {
1996 +               ip_ct_gre_keymap_destroy(&exp);
1997 +               DEBUGP("cannot expect_related()\n");
1998 +               return 1;
1999 +       }
2000 +
2001 +       /* tuple in reply direction, PAC->PNS */
2002 +       exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
2003 +       exp.tuple.src.u.gre.key = htonl(ntohs(callid));
2004 +       exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
2005 +       exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
2006 +
2007 +       DEBUGP("calling expect_related ");
2008 +       DUMP_TUPLE_RAW(&exp.tuple);
2009 +       
2010 +       /* Add GRE keymap entries */
2011 +       ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
2012 +       invert_tuplepr(&inv_tuple, &exp.tuple);
2013 +       ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
2014 +       /* FIXME: cannot handle error correctly, since we need to free
2015 +        * the above keymap :( */
2016 +       
2017 +       if (ip_conntrack_expect_related(master, &exp) != 0) {
2018 +               /* free the second pair of keypmaps */
2019 +               ip_ct_gre_keymap_destroy(&exp);
2020 +               DEBUGP("cannot expect_related():\n");
2021 +               return 1;
2022 +       }
2023 +
2024 +       return 0;
2025 +}
2026 +
2027 +static inline int 
2028 +pptp_inbound_pkt(struct tcphdr *tcph,
2029 +                struct pptp_pkt_hdr *pptph, 
2030 +                size_t datalen,
2031 +                struct ip_conntrack *ct,
2032 +                enum ip_conntrack_info ctinfo)
2033 +{
2034 +       struct PptpControlHeader *ctlh;
2035 +        union pptp_ctrl_union pptpReq;
2036 +       
2037 +       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2038 +       u_int16_t msg, *cid, *pcid;
2039 +       u_int32_t seq;  
2040 +
2041 +       ctlh = (struct PptpControlHeader *) 
2042 +               ((char *) pptph + sizeof(struct pptp_pkt_hdr));
2043 +       pptpReq.rawreq = (void *) 
2044 +               ((char *) ctlh + sizeof(struct PptpControlHeader));
2045 +
2046 +       msg = ntohs(ctlh->messageType);
2047 +       DEBUGP("inbound control message %s\n", strMName[msg]);
2048 +
2049 +       switch (msg) {
2050 +       case PPTP_START_SESSION_REPLY:
2051 +               /* server confirms new control session */
2052 +               if (info->sstate < PPTP_SESSION_REQUESTED) {
2053 +                       DEBUGP("%s without START_SESS_REQUEST\n",
2054 +                               strMName[msg]);
2055 +                       break;
2056 +               }
2057 +               if (pptpReq.srep->resultCode == PPTP_START_OK)
2058 +                       info->sstate = PPTP_SESSION_CONFIRMED;
2059 +               else 
2060 +                       info->sstate = PPTP_SESSION_ERROR;
2061 +               break;
2062 +
2063 +       case PPTP_STOP_SESSION_REPLY:
2064 +               /* server confirms end of control session */
2065 +               if (info->sstate > PPTP_SESSION_STOPREQ) {
2066 +                       DEBUGP("%s without STOP_SESS_REQUEST\n",
2067 +                               strMName[msg]);
2068 +                       break;
2069 +               }
2070 +               if (pptpReq.strep->resultCode == PPTP_STOP_OK)
2071 +                       info->sstate = PPTP_SESSION_NONE;
2072 +               else
2073 +                       info->sstate = PPTP_SESSION_ERROR;
2074 +               break;
2075 +
2076 +       case PPTP_OUT_CALL_REPLY:
2077 +               /* server accepted call, we now expect GRE frames */
2078 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2079 +                       DEBUGP("%s but no session\n", strMName[msg]);
2080 +                       break;
2081 +               }
2082 +               if (info->cstate != PPTP_CALL_OUT_REQ &&
2083 +                   info->cstate != PPTP_CALL_OUT_CONF) {
2084 +                       DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
2085 +                       break;
2086 +               }
2087 +               if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
2088 +                       info->cstate = PPTP_CALL_NONE;
2089 +                       break;
2090 +               }
2091 +
2092 +               cid = &pptpReq.ocack->callID;
2093 +               pcid = &pptpReq.ocack->peersCallID;
2094 +
2095 +               info->pac_call_id = ntohs(*cid);
2096 +               
2097 +               if (htons(info->pns_call_id) != *pcid) {
2098 +                       DEBUGP("%s for unknown callid %u\n",
2099 +                               strMName[msg], ntohs(*pcid));
2100 +                       break;
2101 +               }
2102 +
2103 +               DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], 
2104 +                       ntohs(*cid), ntohs(*pcid));
2105 +               
2106 +               info->cstate = PPTP_CALL_OUT_CONF;
2107 +
2108 +               seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2109 +               if (exp_gre(ct, seq, *cid, *pcid) != 0)
2110 +                       printk("ip_conntrack_pptp: error during exp_gre\n");
2111 +               break;
2112 +
2113 +       case PPTP_IN_CALL_REQUEST:
2114 +               /* server tells us about incoming call request */
2115 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2116 +                       DEBUGP("%s but no session\n", strMName[msg]);
2117 +                       break;
2118 +               }
2119 +               pcid = &pptpReq.icack->peersCallID;
2120 +               DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2121 +               info->cstate = PPTP_CALL_IN_REQ;
2122 +               info->pac_call_id= ntohs(*pcid);
2123 +               break;
2124 +
2125 +       case PPTP_IN_CALL_CONNECT:
2126 +               /* server tells us about incoming call established */
2127 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2128 +                       DEBUGP("%s but no session\n", strMName[msg]);
2129 +                       break;
2130 +               }
2131 +               if (info->sstate != PPTP_CALL_IN_REP
2132 +                   && info->sstate != PPTP_CALL_IN_CONF) {
2133 +                       DEBUGP("%s but never sent IN_CALL_REPLY\n",
2134 +                               strMName[msg]);
2135 +                       break;
2136 +               }
2137 +
2138 +               pcid = &pptpReq.iccon->peersCallID;
2139 +               cid = &info->pac_call_id;
2140 +
2141 +               if (info->pns_call_id != ntohs(*pcid)) {
2142 +                       DEBUGP("%s for unknown CallID %u\n", 
2143 +                               strMName[msg], ntohs(*cid));
2144 +                       break;
2145 +               }
2146 +
2147 +               DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2148 +               info->cstate = PPTP_CALL_IN_CONF;
2149 +
2150 +               /* we expect a GRE connection from PAC to PNS */
2151 +               seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2152 +               if (exp_gre(ct, seq, *cid, *pcid) != 0)
2153 +                       printk("ip_conntrack_pptp: error during exp_gre\n");
2154 +
2155 +               break;
2156 +
2157 +       case PPTP_CALL_DISCONNECT_NOTIFY:
2158 +               /* server confirms disconnect */
2159 +               cid = &pptpReq.disc->callID;
2160 +               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2161 +               info->cstate = PPTP_CALL_NONE;
2162 +
2163 +               /* untrack this call id, unexpect GRE packets */
2164 +               pptp_timeout_related(ct);
2165 +               break;
2166 +
2167 +       case PPTP_WAN_ERROR_NOTIFY:
2168 +               break;
2169 +
2170 +       case PPTP_ECHO_REQUEST:
2171 +       case PPTP_ECHO_REPLY:
2172 +               /* I don't have to explain these ;) */
2173 +               break;
2174 +       default:
2175 +               DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
2176 +                       ? strMName[msg]:strMName[0], msg);
2177 +               break;
2178 +       }
2179 +
2180 +       return NF_ACCEPT;
2181 +
2182 +}
2183 +
2184 +static inline int
2185 +pptp_outbound_pkt(struct tcphdr *tcph,
2186 +                 struct pptp_pkt_hdr *pptph,
2187 +                 size_t datalen,
2188 +                 struct ip_conntrack *ct,
2189 +                 enum ip_conntrack_info ctinfo)
2190 +{
2191 +       struct PptpControlHeader *ctlh;
2192 +        union pptp_ctrl_union pptpReq;
2193 +       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2194 +       u_int16_t msg, *cid, *pcid;
2195 +
2196 +       ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
2197 +       pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
2198 +
2199 +       msg = ntohs(ctlh->messageType);
2200 +       DEBUGP("outbound control message %s\n", strMName[msg]);
2201 +
2202 +       switch (msg) {
2203 +       case PPTP_START_SESSION_REQUEST:
2204 +               /* client requests for new control session */
2205 +               if (info->sstate != PPTP_SESSION_NONE) {
2206 +                       DEBUGP("%s but we already have one",
2207 +                               strMName[msg]);
2208 +               }
2209 +               info->sstate = PPTP_SESSION_REQUESTED;
2210 +               break;
2211 +       case PPTP_STOP_SESSION_REQUEST:
2212 +               /* client requests end of control session */
2213 +               info->sstate = PPTP_SESSION_STOPREQ;
2214 +               break;
2215 +
2216 +       case PPTP_OUT_CALL_REQUEST:
2217 +               /* client initiating connection to server */
2218 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2219 +                       DEBUGP("%s but no session\n",
2220 +                               strMName[msg]);
2221 +                       break;
2222 +               }
2223 +               info->cstate = PPTP_CALL_OUT_REQ;
2224 +               /* track PNS call id */
2225 +               cid = &pptpReq.ocreq->callID;
2226 +               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2227 +               info->pns_call_id = ntohs(*cid);
2228 +               break;
2229 +       case PPTP_IN_CALL_REPLY:
2230 +               /* client answers incoming call */
2231 +               if (info->cstate != PPTP_CALL_IN_REQ
2232 +                   && info->cstate != PPTP_CALL_IN_REP) {
2233 +                       DEBUGP("%s without incall_req\n", 
2234 +                               strMName[msg]);
2235 +                       break;
2236 +               }
2237 +               if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
2238 +                       info->cstate = PPTP_CALL_NONE;
2239 +                       break;
2240 +               }
2241 +               pcid = &pptpReq.icack->peersCallID;
2242 +               if (info->pac_call_id != ntohs(*pcid)) {
2243 +                       DEBUGP("%s for unknown call %u\n", 
2244 +                               strMName[msg], ntohs(*pcid));
2245 +                       break;
2246 +               }
2247 +               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
2248 +               /* part two of the three-way handshake */
2249 +               info->cstate = PPTP_CALL_IN_REP;
2250 +               info->pns_call_id = ntohs(pptpReq.icack->callID);
2251 +               break;
2252 +
2253 +       case PPTP_CALL_CLEAR_REQUEST:
2254 +               /* client requests hangup of call */
2255 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2256 +                       DEBUGP("CLEAR_CALL but no session\n");
2257 +                       break;
2258 +               }
2259 +               /* FUTURE: iterate over all calls and check if
2260 +                * call ID is valid.  We don't do this without newnat,
2261 +                * because we only know about last call */
2262 +               info->cstate = PPTP_CALL_CLEAR_REQ;
2263 +               break;
2264 +       case PPTP_SET_LINK_INFO:
2265 +               break;
2266 +       case PPTP_ECHO_REQUEST:
2267 +       case PPTP_ECHO_REPLY:
2268 +               /* I don't have to explain these ;) */
2269 +               break;
2270 +       default:
2271 +               DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? 
2272 +                       strMName[msg]:strMName[0], msg);
2273 +               /* unknown: no need to create GRE masq table entry */
2274 +               break;
2275 +       }
2276 +
2277 +       return NF_ACCEPT;
2278 +}
2279 +
2280 +
2281 +/* track caller id inside control connection, call expect_related */
2282 +static int 
2283 +conntrack_pptp_help(const struct iphdr *iph, size_t len,
2284 +                   struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
2285 +
2286 +{
2287 +       struct pptp_pkt_hdr *pptph;
2288 +       
2289 +       struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
2290 +       u_int32_t tcplen = len - iph->ihl * 4;
2291 +       u_int32_t datalen = tcplen - tcph->doff * 4;
2292 +       void *datalimit;
2293 +       int dir = CTINFO2DIR(ctinfo);
2294 +       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2295 +
2296 +       int oldsstate, oldcstate;
2297 +       int ret;
2298 +
2299 +       /* don't do any tracking before tcp handshake complete */
2300 +       if (ctinfo != IP_CT_ESTABLISHED 
2301 +           && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
2302 +               DEBUGP("ctinfo = %u, skipping\n", ctinfo);
2303 +               return NF_ACCEPT;
2304 +       }
2305 +       
2306 +       /* not a complete TCP header? */
2307 +       if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
2308 +               DEBUGP("tcplen = %u\n", tcplen);
2309 +               return NF_ACCEPT;
2310 +       }
2311 +
2312 +       /* checksum invalid? */
2313 +       if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
2314 +                       csum_partial((char *) tcph, tcplen, 0))) {
2315 +               printk(KERN_NOTICE __FILE__ ": bad csum\n");
2316 +               /* W2K PPTP server sends TCP packets with wrong checksum :(( */
2317 +               //return NF_ACCEPT;
2318 +       }
2319 +
2320 +       if (tcph->fin || tcph->rst) {
2321 +               DEBUGP("RST/FIN received, timeouting GRE\n");
2322 +               /* can't do this after real newnat */
2323 +               info->cstate = PPTP_CALL_NONE;
2324 +
2325 +               /* untrack this call id, unexpect GRE packets */
2326 +               pptp_timeout_related(ct);
2327 +       }
2328 +
2329 +
2330 +       pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
2331 +       datalimit = (void *) pptph + datalen;
2332 +
2333 +       /* not a full pptp packet header? */
2334 +       if ((void *) pptph+sizeof(*pptph) >= datalimit) {
2335 +               DEBUGP("no full PPTP header, can't track\n");
2336 +               return NF_ACCEPT;
2337 +       }
2338 +       
2339 +       /* if it's not a control message we can't do anything with it */
2340 +        if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
2341 +           ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
2342 +               DEBUGP("not a control packet\n");
2343 +               return NF_ACCEPT;
2344 +       }
2345 +
2346 +       oldsstate = info->sstate;
2347 +       oldcstate = info->cstate;
2348 +
2349 +       LOCK_BH(&ip_pptp_lock);
2350 +
2351 +       /* FIXME: We just blindly assume that the control connection is always
2352 +        * established from PNS->PAC.  However, RFC makes no guarantee */
2353 +       if (dir == IP_CT_DIR_ORIGINAL)
2354 +               /* client -> server (PNS -> PAC) */
2355 +               ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2356 +       else
2357 +               /* server -> client (PAC -> PNS) */
2358 +               ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2359 +       DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
2360 +               oldsstate, info->sstate, oldcstate, info->cstate);
2361 +       UNLOCK_BH(&ip_pptp_lock);
2362 +
2363 +       return ret;
2364 +}
2365 +
2366 +/* control protocol helper */
2367 +static struct ip_conntrack_helper pptp = { 
2368 +       .list = { NULL, NULL },
2369 +       .name = "pptp", 
2370 +       .flags = IP_CT_HELPER_F_REUSE_EXPECT,
2371 +       .me = THIS_MODULE,
2372 +       .max_expected = 2,
2373 +       .timeout = 0,
2374 +       .tuple = { .src = { .ip = 0, 
2375 +                           .u = { .tcp = { .port =  
2376 +                                   __constant_htons(PPTP_CONTROL_PORT) } } 
2377 +                         }, 
2378 +                  .dst = { .ip = 0, 
2379 +                           .u = { .all = 0 },
2380 +                           .protonum = IPPROTO_TCP
2381 +                         } 
2382 +                },
2383 +       .mask = { .src = { .ip = 0, 
2384 +                          .u = { .tcp = { .port = 0xffff } } 
2385 +                        }, 
2386 +                 .dst = { .ip = 0, 
2387 +                          .u = { .all = 0 },
2388 +                          .protonum = 0xffff 
2389 +                        } 
2390 +               },
2391 +       .help = conntrack_pptp_help
2392 +};
2393 +
2394 +/* ip_conntrack_pptp initialization */
2395 +static int __init init(void)
2396 +{
2397 +       int retcode;
2398 +
2399 +       DEBUGP(__FILE__ ": registering helper\n");
2400 +       if ((retcode = ip_conntrack_helper_register(&pptp))) {
2401 +                printk(KERN_ERR "Unable to register conntrack application "
2402 +                               "helper for pptp: %d\n", retcode);
2403 +               return -EIO;
2404 +       }
2405 +
2406 +       printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
2407 +       return 0;
2408 +}
2409 +
2410 +static void __exit fini(void)
2411 +{
2412 +       ip_conntrack_helper_unregister(&pptp);
2413 +       printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
2414 +}
2415 +
2416 +module_init(init);
2417 +module_exit(fini);
2418 +
2419 +EXPORT_SYMBOL(ip_pptp_lock);