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