Merge branch 'org.openembedded.dev' of git@git.openembedded.net:openembedded into...
[openembedded.git] / recipes / linux / linux-mtx-1-2.4.27 / 48-pptp.patch
1 diff -uNr linux_org/Documentation/Configure.help linux/Documentation/Configure.help
2 --- linux_org/Documentation/Configure.help      2006-10-27 14:08:20.000000000 +0200
3 +++ linux/Documentation/Configure.help  2006-10-27 14:11:52.000000000 +0200
4 @@ -2848,6 +2848,31 @@
5    If you want to compile it as a module, say M here and read
6    <file:Documentation/modules.txt>.  If unsure, say `Y'.
7  
8 +PPTP conntrack and NAT support
9 +CONFIG_IP_NF_PPTP
10 +  This module adds support for PPTP (Point to Point Tunnelling Protocol, 
11 +  RFC2637) conncection tracking and NAT. 
12 +
13 +  If you are running PPTP sessions over a stateful firewall or NAT box,
14 +  you may want to enable this feature.  
15 +
16 +  Please note that not all PPTP modes of operation are supported yet.
17 +  For more info, read top of the file net/ipv4/netfilter/ip_conntrack_pptp.c
18 +
19 +  If you want to compile it as a module, say M here and read
20 +  Documentation/modules.txt.  If unsure, say `N'.
21 +
22 +GRE protocol conntrack and NAT support
23 +CONFIG_IP_NF_CT_PROTO_GRE
24 +  This module adds generic support for connection tracking and NAT of the
25 +  GRE protocol (RFC1701, RFC2784).  Please note that this will only work
26 +  with GRE connections using the key field of the GRE header.
27 +
28 +  You will need GRE support to enable PPTP support.
29 +
30 +  If you want to compile it as a module, say `M' here and read
31 +  Documentation/modules.txt.  If unsire, say `N'.
32 +
33  User space queueing via NETLINK
34  CONFIG_IP_NF_QUEUE
35    Netfilter has the ability to queue packets to user space: the
36 diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack.h linux/include/linux/netfilter_ipv4/ip_conntrack.h
37 --- linux_org/include/linux/netfilter_ipv4/ip_conntrack.h       2004-11-24 12:13:57.000000000 +0100
38 +++ linux/include/linux/netfilter_ipv4/ip_conntrack.h   2006-10-27 14:11:52.000000000 +0200
39 @@ -50,19 +50,23 @@
40  
41  #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
42  #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
43 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
44  
45  /* per conntrack: protocol private data */
46  union ip_conntrack_proto {
47         /* insert conntrack proto private data here */
48 +       struct ip_ct_gre gre;
49         struct ip_ct_tcp tcp;
50         struct ip_ct_icmp icmp;
51  };
52  
53  union ip_conntrack_expect_proto {
54         /* insert expect proto private data here */
55 +       struct ip_ct_gre_expect gre;
56  };
57  
58  /* Add protocol helper include file here */
59 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
60  #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
61  
62  #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
63 @@ -71,6 +75,7 @@
64  /* per expectation: application helper private data */
65  union ip_conntrack_expect_help {
66         /* insert conntrack helper private data (expect) here */
67 +       struct ip_ct_pptp_expect exp_pptp_info;
68         struct ip_ct_amanda_expect exp_amanda_info;
69         struct ip_ct_ftp_expect exp_ftp_info;
70         struct ip_ct_irc_expect exp_irc_info;
71 @@ -85,16 +90,19 @@
72  /* per conntrack: application helper private data */
73  union ip_conntrack_help {
74         /* insert conntrack helper private data (master) here */
75 +       struct ip_ct_pptp_master ct_pptp_info;
76         struct ip_ct_ftp_master ct_ftp_info;
77         struct ip_ct_irc_master ct_irc_info;
78  };
79  
80  #ifdef CONFIG_IP_NF_NAT_NEEDED
81  #include <linux/netfilter_ipv4/ip_nat.h>
82 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
83  
84  /* per conntrack: nat application helper private data */
85  union ip_conntrack_nat_help {
86         /* insert nat helper private data here */
87 +       struct ip_nat_pptp nat_pptp_info;
88  };
89  #endif
90  
91 diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
92 --- linux_org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h  1970-01-01 01:00:00.000000000 +0100
93 +++ linux/include/linux/netfilter_ipv4/ip_conntrack_pptp.h      2006-10-27 14:11:52.000000000 +0200
94 @@ -0,0 +1,313 @@
95 +/* PPTP constants and structs */
96 +#ifndef _CONNTRACK_PPTP_H
97 +#define _CONNTRACK_PPTP_H
98 +
99 +/* state of the control session */
100 +enum pptp_ctrlsess_state {
101 +       PPTP_SESSION_NONE,                      /* no session present */
102 +       PPTP_SESSION_ERROR,                     /* some session error */
103 +       PPTP_SESSION_STOPREQ,                   /* stop_sess request seen */
104 +       PPTP_SESSION_REQUESTED,                 /* start_sess request seen */
105 +       PPTP_SESSION_CONFIRMED,                 /* session established */
106 +};
107 +
108 +/* state of the call inside the control session */
109 +enum pptp_ctrlcall_state {
110 +       PPTP_CALL_NONE,
111 +       PPTP_CALL_ERROR,
112 +       PPTP_CALL_OUT_REQ,
113 +       PPTP_CALL_OUT_CONF,
114 +       PPTP_CALL_IN_REQ,
115 +       PPTP_CALL_IN_REP,
116 +       PPTP_CALL_IN_CONF,
117 +       PPTP_CALL_CLEAR_REQ,
118 +};
119 +
120 +
121 +/* conntrack private data */
122 +struct ip_ct_pptp_master {
123 +       enum pptp_ctrlsess_state sstate;        /* session state */
124 +
125 +       /* everything below is going to be per-expectation in newnat,
126 +        * since there could be more than one call within one session */
127 +       enum pptp_ctrlcall_state cstate;        /* call state */
128 +       u_int16_t pac_call_id;                  /* call id of PAC, host byte order */
129 +       u_int16_t pns_call_id;                  /* call id of PNS, host byte order */
130 +};
131 +
132 +/* conntrack_expect private member */
133 +struct ip_ct_pptp_expect {
134 +       enum pptp_ctrlcall_state cstate;        /* call state */
135 +       u_int16_t pac_call_id;                  /* call id of PAC */
136 +       u_int16_t pns_call_id;                  /* call id of PNS */
137 +};
138 +
139 +
140 +#ifdef __KERNEL__
141 +
142 +#include <linux/netfilter_ipv4/lockhelp.h>
143 +DECLARE_LOCK_EXTERN(ip_pptp_lock);
144 +
145 +#define IP_CONNTR_PPTP         PPTP_CONTROL_PORT
146 +
147 +union pptp_ctrl_union {
148 +                void                           *rawreq;
149 +               struct PptpStartSessionRequest  *sreq;
150 +               struct PptpStartSessionReply    *srep;
151 +               struct PptpStopSessionReqest    *streq;
152 +               struct PptpStopSessionReply     *strep;
153 +                struct PptpOutCallRequest       *ocreq;
154 +                struct PptpOutCallReply         *ocack;
155 +                struct PptpInCallRequest        *icreq;
156 +                struct PptpInCallReply          *icack;
157 +                struct PptpInCallConnected      *iccon;
158 +               struct PptpClearCallRequest     *clrreq;
159 +                struct PptpCallDisconnectNotify *disc;
160 +                struct PptpWanErrorNotify       *wanerr;
161 +                struct PptpSetLinkInfo          *setlink;
162 +};
163 +
164 +
165 +
166 +#define PPTP_CONTROL_PORT      1723
167 +
168 +#define PPTP_PACKET_CONTROL    1
169 +#define PPTP_PACKET_MGMT       2
170 +
171 +#define PPTP_MAGIC_COOKIE      0x1a2b3c4d
172 +
173 +struct pptp_pkt_hdr {
174 +       __u16   packetLength;
175 +       __u16   packetType;
176 +       __u32   magicCookie;
177 +};
178 +
179 +/* PptpControlMessageType values */
180 +#define PPTP_START_SESSION_REQUEST     1
181 +#define PPTP_START_SESSION_REPLY       2
182 +#define PPTP_STOP_SESSION_REQUEST      3
183 +#define PPTP_STOP_SESSION_REPLY                4
184 +#define PPTP_ECHO_REQUEST              5
185 +#define PPTP_ECHO_REPLY                        6
186 +#define PPTP_OUT_CALL_REQUEST          7
187 +#define PPTP_OUT_CALL_REPLY            8
188 +#define PPTP_IN_CALL_REQUEST           9
189 +#define PPTP_IN_CALL_REPLY             10
190 +#define PPTP_IN_CALL_CONNECT           11
191 +#define PPTP_CALL_CLEAR_REQUEST                12
192 +#define PPTP_CALL_DISCONNECT_NOTIFY    13
193 +#define PPTP_WAN_ERROR_NOTIFY          14
194 +#define PPTP_SET_LINK_INFO             15
195 +
196 +#define PPTP_MSG_MAX                   15
197 +
198 +/* PptpGeneralError values */
199 +#define PPTP_ERROR_CODE_NONE           0
200 +#define PPTP_NOT_CONNECTED             1
201 +#define PPTP_BAD_FORMAT                        2
202 +#define PPTP_BAD_VALUE                 3
203 +#define PPTP_NO_RESOURCE               4
204 +#define PPTP_BAD_CALLID                        5
205 +#define PPTP_REMOVE_DEVICE_ERROR       6
206 +
207 +struct PptpControlHeader {
208 +       __u16   messageType;
209 +       __u16   reserved;
210 +};
211 +
212 +/* FramingCapability Bitmap Values */
213 +#define PPTP_FRAME_CAP_ASYNC           0x1
214 +#define PPTP_FRAME_CAP_SYNC            0x2
215 +
216 +/* BearerCapability Bitmap Values */
217 +#define PPTP_BEARER_CAP_ANALOG         0x1
218 +#define PPTP_BEARER_CAP_DIGITAL                0x2
219 +
220 +struct PptpStartSessionRequest {
221 +       __u16   protocolVersion;
222 +       __u8    reserved1;
223 +       __u8    reserved2;
224 +       __u32   framingCapability;
225 +       __u32   bearerCapability;
226 +       __u16   maxChannels;
227 +       __u16   firmwareRevision;
228 +       __u8    hostName[64];
229 +       __u8    vendorString[64];
230 +};
231 +
232 +/* PptpStartSessionResultCode Values */
233 +#define PPTP_START_OK                  1
234 +#define PPTP_START_GENERAL_ERROR       2
235 +#define PPTP_START_ALREADY_CONNECTED   3
236 +#define PPTP_START_NOT_AUTHORIZED      4
237 +#define PPTP_START_UNKNOWN_PROTOCOL    5
238 +
239 +struct PptpStartSessionReply {
240 +       __u16   protocolVersion;
241 +       __u8    resultCode;
242 +       __u8    generalErrorCode;
243 +       __u32   framingCapability;
244 +       __u32   bearerCapability;
245 +       __u16   maxChannels;
246 +       __u16   firmwareRevision;
247 +       __u8    hostName[64];
248 +       __u8    vendorString[64];
249 +};
250 +
251 +/* PptpStopReasons */
252 +#define PPTP_STOP_NONE                 1
253 +#define PPTP_STOP_PROTOCOL             2
254 +#define PPTP_STOP_LOCAL_SHUTDOWN       3
255 +
256 +struct PptpStopSessionRequest {
257 +       __u8    reason;
258 +};
259 +
260 +/* PptpStopSessionResultCode */
261 +#define PPTP_STOP_OK                   1
262 +#define PPTP_STOP_GENERAL_ERROR                2
263 +
264 +struct PptpStopSessionReply {
265 +       __u8    resultCode;
266 +       __u8    generalErrorCode;
267 +};
268 +
269 +struct PptpEchoRequest {
270 +       __u32 identNumber;
271 +};
272 +
273 +/* PptpEchoReplyResultCode */
274 +#define PPTP_ECHO_OK                   1
275 +#define PPTP_ECHO_GENERAL_ERROR                2
276 +
277 +struct PptpEchoReply {
278 +       __u32   identNumber;
279 +       __u8    resultCode;
280 +       __u8    generalErrorCode;
281 +       __u16   reserved;
282 +};
283 +
284 +/* PptpFramingType */
285 +#define PPTP_ASYNC_FRAMING             1
286 +#define PPTP_SYNC_FRAMING              2
287 +#define PPTP_DONT_CARE_FRAMING         3
288 +
289 +/* PptpCallBearerType */
290 +#define PPTP_ANALOG_TYPE               1
291 +#define PPTP_DIGITAL_TYPE              2
292 +#define PPTP_DONT_CARE_BEARER_TYPE     3
293 +
294 +struct PptpOutCallRequest {
295 +       __u16   callID;
296 +       __u16   callSerialNumber;
297 +       __u32   minBPS;
298 +       __u32   maxBPS;
299 +       __u32   bearerType;
300 +       __u32   framingType;
301 +       __u16   packetWindow;
302 +       __u16   packetProcDelay;
303 +       __u16   reserved1;
304 +       __u16   phoneNumberLength;
305 +       __u16   reserved2;
306 +       __u8    phoneNumber[64];
307 +       __u8    subAddress[64];
308 +};
309 +
310 +/* PptpCallResultCode */
311 +#define PPTP_OUTCALL_CONNECT           1
312 +#define PPTP_OUTCALL_GENERAL_ERROR     2
313 +#define PPTP_OUTCALL_NO_CARRIER                3
314 +#define PPTP_OUTCALL_BUSY              4
315 +#define PPTP_OUTCALL_NO_DIAL_TONE      5
316 +#define PPTP_OUTCALL_TIMEOUT           6
317 +#define PPTP_OUTCALL_DONT_ACCEPT       7
318 +
319 +struct PptpOutCallReply {
320 +       __u16   callID;
321 +       __u16   peersCallID;
322 +       __u8    resultCode;
323 +       __u8    generalErrorCode;
324 +       __u16   causeCode;
325 +       __u32   connectSpeed;
326 +       __u16   packetWindow;
327 +       __u16   packetProcDelay;
328 +       __u32   physChannelID;
329 +};
330 +
331 +struct PptpInCallRequest {
332 +       __u16   callID;
333 +       __u16   callSerialNumber;
334 +       __u32   callBearerType;
335 +       __u32   physChannelID;
336 +       __u16   dialedNumberLength;
337 +       __u16   dialingNumberLength;
338 +       __u8    dialedNumber[64];
339 +       __u8    dialingNumber[64];
340 +       __u8    subAddress[64];
341 +};
342 +
343 +/* PptpInCallResultCode */
344 +#define PPTP_INCALL_ACCEPT             1
345 +#define PPTP_INCALL_GENERAL_ERROR      2
346 +#define PPTP_INCALL_DONT_ACCEPT                3
347 +
348 +struct PptpInCallReply {
349 +       __u16   callID;
350 +       __u16   peersCallID;
351 +       __u8    resultCode;
352 +       __u8    generalErrorCode;
353 +       __u16   packetWindow;
354 +       __u16   packetProcDelay;
355 +       __u16   reserved;
356 +};
357 +
358 +struct PptpInCallConnected {
359 +       __u16   peersCallID;
360 +       __u16   reserved;
361 +       __u32   connectSpeed;
362 +       __u16   packetWindow;
363 +       __u16   packetProcDelay;
364 +       __u32   callFramingType;
365 +};
366 +
367 +struct PptpClearCallRequest {
368 +       __u16   callID;
369 +       __u16   reserved;
370 +};
371 +
372 +struct PptpCallDisconnectNotify {
373 +       __u16   callID;
374 +       __u8    resultCode;
375 +       __u8    generalErrorCode;
376 +       __u16   causeCode;
377 +       __u16   reserved;
378 +       __u8    callStatistics[128];
379 +};
380 +
381 +struct PptpWanErrorNotify {
382 +       __u16   peersCallID;
383 +       __u16   reserved;
384 +       __u32   crcErrors;
385 +       __u32   framingErrors;
386 +       __u32   hardwareOverRuns;
387 +       __u32   bufferOverRuns;
388 +       __u32   timeoutErrors;
389 +       __u32   alignmentErrors;
390 +};
391 +
392 +struct PptpSetLinkInfo {
393 +       __u16   peersCallID;
394 +       __u16   reserved;
395 +       __u32   sendAccm;
396 +       __u32   recvAccm;
397 +};
398 +
399 +
400 +struct pptp_priv_data {
401 +       __u16   call_id;
402 +       __u16   mcall_id;
403 +       __u16   pcall_id;
404 +};
405 +
406 +#endif /* __KERNEL__ */
407 +#endif /* _CONNTRACK_PPTP_H */
408 diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
409 --- linux_org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h     1970-01-01 01:00:00.000000000 +0100
410 +++ linux/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2006-10-27 14:11:52.000000000 +0200
411 @@ -0,0 +1,123 @@
412 +#ifndef _CONNTRACK_PROTO_GRE_H
413 +#define _CONNTRACK_PROTO_GRE_H
414 +#include <asm/byteorder.h>
415 +
416 +/* GRE PROTOCOL HEADER */
417 +
418 +/* GRE Version field */
419 +#define GRE_VERSION_1701       0x0
420 +#define GRE_VERSION_PPTP       0x1
421 +
422 +/* GRE Protocol field */
423 +#define GRE_PROTOCOL_PPTP      0x880B
424 +
425 +/* GRE Flags */
426 +#define GRE_FLAG_C             0x80
427 +#define GRE_FLAG_R             0x40
428 +#define GRE_FLAG_K             0x20
429 +#define GRE_FLAG_S             0x10
430 +#define GRE_FLAG_A             0x80
431 +
432 +#define GRE_IS_C(f)    ((f)&GRE_FLAG_C)
433 +#define GRE_IS_R(f)    ((f)&GRE_FLAG_R)
434 +#define GRE_IS_K(f)    ((f)&GRE_FLAG_K)
435 +#define GRE_IS_S(f)    ((f)&GRE_FLAG_S)
436 +#define GRE_IS_A(f)    ((f)&GRE_FLAG_A)
437 +
438 +/* GRE is a mess: Four different standards */
439 +struct gre_hdr {
440 +#if defined(__LITTLE_ENDIAN_BITFIELD)
441 +       __u16   rec:3,
442 +               srr:1,
443 +               seq:1,
444 +               key:1,
445 +               routing:1,
446 +               csum:1,
447 +               version:3,
448 +               reserved:4,
449 +               ack:1;
450 +#elif defined(__BIG_ENDIAN_BITFIELD)
451 +       __u16   csum:1,
452 +               routing:1,
453 +               key:1,
454 +               seq:1,
455 +               srr:1,
456 +               rec:3,
457 +               ack:1,
458 +               reserved:4,
459 +               version:3;
460 +#else
461 +#error "Adjust your <asm/byteorder.h> defines"
462 +#endif
463 +       __u16   protocol;
464 +};
465 +
466 +/* modified GRE header for PPTP */
467 +struct gre_hdr_pptp {
468 +       __u8  flags;            /* bitfield */
469 +       __u8  version;          /* should be GRE_VERSION_PPTP */
470 +       __u16 protocol;         /* should be GRE_PROTOCOL_PPTP */
471 +       __u16 payload_len;      /* size of ppp payload, not inc. gre header */
472 +       __u16 call_id;          /* peer's call_id for this session */
473 +       __u32 seq;              /* sequence number.  Present if S==1 */
474 +       __u32 ack;              /* seq number of highest packet recieved by */
475 +                               /*  sender in this session */
476 +};
477 +
478 +
479 +/* this is part of ip_conntrack */
480 +struct ip_ct_gre {
481 +       unsigned int stream_timeout;
482 +       unsigned int timeout;
483 +};
484 +
485 +/* this is part of ip_conntrack_expect */
486 +struct ip_ct_gre_expect {
487 +       struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
488 +};
489 +
490 +#ifdef __KERNEL__
491 +struct ip_conntrack_expect;
492 +
493 +/* structure for original <-> reply keymap */
494 +struct ip_ct_gre_keymap {
495 +       struct list_head list;
496 +
497 +       struct ip_conntrack_tuple tuple;
498 +};
499 +
500 +
501 +/* add new tuple->key_reply pair to keymap */
502 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
503 +                        struct ip_conntrack_tuple *t,
504 +                        int reply);
505 +
506 +/* change an existing keymap entry */
507 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
508 +                            struct ip_conntrack_tuple *t);
509 +
510 +/* delete keymap entries */
511 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
512 +
513 +
514 +/* get pointer to gre key, if present */
515 +static inline u_int32_t *gre_key(struct gre_hdr *greh)
516 +{
517 +       if (!greh->key)
518 +               return NULL;
519 +       if (greh->csum || greh->routing)
520 +               return (u_int32_t *) (greh+sizeof(*greh)+4);
521 +       return (u_int32_t *) (greh+sizeof(*greh));
522 +}
523 +
524 +/* get pointer ot gre csum, if present */
525 +static inline u_int16_t *gre_csum(struct gre_hdr *greh)
526 +{
527 +       if (!greh->csum)
528 +               return NULL;
529 +       return (u_int16_t *) (greh+sizeof(*greh));
530 +}
531 +
532 +#endif /* __KERNEL__ */
533 +
534 +#endif /* _CONNTRACK_PROTO_GRE_H */
535 diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
536 --- linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-11-17 02:07:46.000000000 +0100
537 +++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h     2006-10-27 14:11:52.000000000 +0200
538 @@ -14,7 +14,7 @@
539  union ip_conntrack_manip_proto
540  {
541         /* Add other protocols here. */
542 -       u_int16_t all;
543 +       u_int32_t all;
544  
545         struct {
546                 u_int16_t port;
547 @@ -25,6 +25,9 @@
548         struct {
549                 u_int16_t id;
550         } icmp;
551 +       struct {
552 +               u_int32_t key;
553 +       } gre;
554  };
555  
556  /* The manipulable part of the tuple. */
557 @@ -44,7 +47,7 @@
558                 u_int32_t ip;
559                 union {
560                         /* Add other protocols here. */
561 -                       u_int16_t all;
562 +                       u_int64_t all;
563  
564                         struct {
565                                 u_int16_t port;
566 @@ -55,6 +58,11 @@
567                         struct {
568                                 u_int8_t type, code;
569                         } icmp;
570 +                       struct {
571 +                               u_int16_t protocol;
572 +                               u_int8_t version;
573 +                               u_int32_t key;
574 +                       } gre;
575                 } u;
576  
577                 /* The protocol. */
578 @@ -80,10 +88,16 @@
579  #ifdef __KERNEL__
580  
581  #define DUMP_TUPLE(tp)                                         \
582 -DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",    \
583 +DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n",      \
584         (tp), (tp)->dst.protonum,                               \
585 -       NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all),          \
586 -       NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
587 +       NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all),          \
588 +       NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all))
589 +
590 +#define DUMP_TUPLE_RAW(x)                                              \
591 +       DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\
592 +       (x), (x)->dst.protonum,                                         \
593 +       NIPQUAD((x)->src.ip), ntohl((x)->src.u.all),                    \
594 +       NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all))
595  
596  #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
597  
598 diff -uNr linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig
599 --- linux_org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig    1970-01-01 01:00:00.000000000 +0100
600 +++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h.orig        2003-11-17 02:07:46.000000000 +0100
601 @@ -0,0 +1,139 @@
602 +#ifndef _IP_CONNTRACK_TUPLE_H
603 +#define _IP_CONNTRACK_TUPLE_H
604 +
605 +/* A `tuple' is a structure containing the information to uniquely
606 +  identify a connection.  ie. if two packets have the same tuple, they
607 +  are in the same connection; if not, they are not.
608 +
609 +  We divide the structure along "manipulatable" and
610 +  "non-manipulatable" lines, for the benefit of the NAT code.
611 +*/
612 +
613 +/* The protocol-specific manipulable parts of the tuple: always in
614 +   network order! */
615 +union ip_conntrack_manip_proto
616 +{
617 +       /* Add other protocols here. */
618 +       u_int16_t all;
619 +
620 +       struct {
621 +               u_int16_t port;
622 +       } tcp;
623 +       struct {
624 +               u_int16_t port;
625 +       } udp;
626 +       struct {
627 +               u_int16_t id;
628 +       } icmp;
629 +};
630 +
631 +/* The manipulable part of the tuple. */
632 +struct ip_conntrack_manip
633 +{
634 +       u_int32_t ip;
635 +       union ip_conntrack_manip_proto u;
636 +};
637 +
638 +/* This contains the information to distinguish a connection. */
639 +struct ip_conntrack_tuple
640 +{
641 +       struct ip_conntrack_manip src;
642 +
643 +       /* These are the parts of the tuple which are fixed. */
644 +       struct {
645 +               u_int32_t ip;
646 +               union {
647 +                       /* Add other protocols here. */
648 +                       u_int16_t all;
649 +
650 +                       struct {
651 +                               u_int16_t port;
652 +                       } tcp;
653 +                       struct {
654 +                               u_int16_t port;
655 +                       } udp;
656 +                       struct {
657 +                               u_int8_t type, code;
658 +                       } icmp;
659 +               } u;
660 +
661 +               /* The protocol. */
662 +               u_int16_t protonum;
663 +       } dst;
664 +};
665 +
666 +/* This is optimized opposed to a memset of the whole structure.  Everything we
667 + * really care about is the  source/destination unions */
668 +#define IP_CT_TUPLE_U_BLANK(tuple)                             \
669 +       do {                                                    \
670 +               (tuple)->src.u.all = 0;                         \
671 +               (tuple)->dst.u.all = 0;                         \
672 +       } while (0)
673 +
674 +enum ip_conntrack_dir
675 +{
676 +       IP_CT_DIR_ORIGINAL,
677 +       IP_CT_DIR_REPLY,
678 +       IP_CT_DIR_MAX
679 +};
680 +
681 +#ifdef __KERNEL__
682 +
683 +#define DUMP_TUPLE(tp)                                         \
684 +DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n",    \
685 +       (tp), (tp)->dst.protonum,                               \
686 +       NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all),          \
687 +       NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
688 +
689 +#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
690 +
691 +/* If we're the first tuple, it's the original dir. */
692 +#define DIRECTION(h) ((enum ip_conntrack_dir)(&(h)->ctrack->tuplehash[1] == (h)))
693 +
694 +/* Connections have two entries in the hash table: one for each way */
695 +struct ip_conntrack_tuple_hash
696 +{
697 +       struct list_head list;
698 +
699 +       struct ip_conntrack_tuple tuple;
700 +
701 +       /* this == &ctrack->tuplehash[DIRECTION(this)]. */
702 +       struct ip_conntrack *ctrack;
703 +};
704 +
705 +#endif /* __KERNEL__ */
706 +
707 +static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
708 +                                       const struct ip_conntrack_tuple *t2)
709 +{
710 +       return t1->src.ip == t2->src.ip
711 +               && t1->src.u.all == t2->src.u.all;
712 +}
713 +
714 +static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
715 +                                       const struct ip_conntrack_tuple *t2)
716 +{
717 +       return t1->dst.ip == t2->dst.ip
718 +               && t1->dst.u.all == t2->dst.u.all
719 +               && t1->dst.protonum == t2->dst.protonum;
720 +}
721 +
722 +static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
723 +                                   const struct ip_conntrack_tuple *t2)
724 +{
725 +       return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
726 +}
727 +
728 +static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
729 +                                      const struct ip_conntrack_tuple *tuple,
730 +                                      const struct ip_conntrack_tuple *mask)
731 +{
732 +       return !(((t->src.ip ^ tuple->src.ip) & mask->src.ip)
733 +                || ((t->dst.ip ^ tuple->dst.ip) & mask->dst.ip)
734 +                || ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all)
735 +                || ((t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all)
736 +                || ((t->dst.protonum ^ tuple->dst.protonum)
737 +                    & mask->dst.protonum));
738 +}
739 +
740 +#endif /* _IP_CONNTRACK_TUPLE_H */
741 diff -uNr linux_org/include/linux/netfilter_ipv4/ip_nat_pptp.h linux/include/linux/netfilter_ipv4/ip_nat_pptp.h
742 --- linux_org/include/linux/netfilter_ipv4/ip_nat_pptp.h        1970-01-01 01:00:00.000000000 +0100
743 +++ linux/include/linux/netfilter_ipv4/ip_nat_pptp.h    2006-10-27 14:11:52.000000000 +0200
744 @@ -0,0 +1,11 @@
745 +/* PPTP constants and structs */
746 +#ifndef _NAT_PPTP_H
747 +#define _NAT_PPTP_H
748 +
749 +/* conntrack private data */
750 +struct ip_nat_pptp {
751 +       u_int16_t pns_call_id;          /* NAT'ed PNS call id */
752 +       u_int16_t pac_call_id;          /* NAT'ed PAC call id */
753 +};
754 +
755 +#endif /* _NAT_PPTP_H */
756 diff -uNr linux_org/net/ipv4/netfilter/Config.in linux/net/ipv4/netfilter/Config.in
757 --- linux_org/net/ipv4/netfilter/Config.in      2003-08-13 19:19:30.000000000 +0200
758 +++ linux/net/ipv4/netfilter/Config.in  2006-10-27 14:11:52.000000000 +0200
759 @@ -7,6 +7,11 @@
760  tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK
761  if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
762    dep_tristate '  FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
763 +  dep_tristate '  GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
764 +  dep_tristate '  PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CONNTRACK
765 +  if [ "$CONFIG_IP_NF_PPTP" != "n" ]; then
766 +       bool   '    PPTP verbose debug' CONFIG_IP_NF_PPTP_DEBUG
767 +  fi
768    dep_tristate '  Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
769    dep_tristate '  TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
770    dep_tristate '  IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
771 @@ -67,6 +72,20 @@
772          fi
773        fi
774        bool '    NAT of local connections (READ HELP)' CONFIG_IP_NF_NAT_LOCAL
775 +      if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then
776 +        define_tristate CONFIG_IP_NF_NAT_PPTP m
777 +      else
778 +        if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then
779 +          define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT
780 +        fi
781 +      fi
782 +      if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then
783 +        define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m
784 +      else
785 +        if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then
786 +         define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
787 +       fi
788 +      fi
789        if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
790          dep_tristate '    Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
791        fi
792 diff -uNr linux_org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile
793 --- linux_org/net/ipv4/netfilter/Makefile       2003-08-13 19:19:30.000000000 +0200
794 +++ linux/net/ipv4/netfilter/Makefile   2006-10-27 14:11:52.000000000 +0200
795 @@ -30,8 +30,21 @@
796  
797  # connection tracking
798  obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
799
800 +# connection tracking protocol helpers
801 +obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
802 +ifdef CONFIG_IP_NF_CT_PROTO_GRE
803 +       export-objs += ip_conntrack_proto_gre.o
804 +endif
805 +
806 +# NAT protocol helpers
807 +obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
808  
809  # connection tracking helpers
810 +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
811 +ifdef CONFIG_IP_NF_NAT_PPTP
812 +       export-objs += ip_conntrack_pptp.o
813 +endif
814  obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
815  ifdef CONFIG_IP_NF_AMANDA
816         export-objs += ip_conntrack_amanda.o
817 @@ -49,6 +62,7 @@
818  endif
819  
820  # NAT helpers 
821 +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
822  obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
823  obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
824  obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
825 diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_core.c linux/net/ipv4/netfilter/ip_conntrack_core.c
826 --- linux_org/net/ipv4/netfilter/ip_conntrack_core.c    2004-11-24 12:14:04.000000000 +0100
827 +++ linux/net/ipv4/netfilter/ip_conntrack_core.c        2006-10-27 14:11:52.000000000 +0200
828 @@ -142,6 +142,8 @@
829         tuple->dst.ip = iph->daddr;
830         tuple->dst.protonum = iph->protocol;
831  
832 +       tuple->src.u.all = tuple->dst.u.all = 0;
833 +
834         ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
835                                      len - 4*iph->ihl,
836                                      tuple);
837 @@ -157,6 +159,8 @@
838         inverse->dst.ip = orig->src.ip;
839         inverse->dst.protonum = orig->dst.protonum;
840  
841 +       inverse->src.u.all = inverse->dst.u.all = 0;
842 +
843         return protocol->invert_tuple(inverse, orig);
844  }
845  
846 @@ -945,8 +949,8 @@
847          * so there is no need to use the tuple lock too */
848  
849         DEBUGP("ip_conntrack_expect_related %p\n", related_to);
850 -       DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
851 -       DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
852 +       DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
853 +       DEBUGP("mask:  "); DUMP_TUPLE_RAW(&expect->mask);
854  
855         old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
856                         struct ip_conntrack_expect *, &expect->tuple, 
857 @@ -1063,15 +1067,14 @@
858  
859         MUST_BE_READ_LOCKED(&ip_conntrack_lock);
860         WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
861 -
862         DEBUGP("change_expect:\n");
863 -       DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
864 -       DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
865 -       DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
866 +       DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
867 +       DEBUGP("exp mask:  "); DUMP_TUPLE_RAW(&expect->mask);
868 +       DEBUGP("newtuple:  "); DUMP_TUPLE_RAW(newtuple);
869         if (expect->ct_tuple.dst.protonum == 0) {
870                 /* Never seen before */
871                 DEBUGP("change expect: never seen before\n");
872 -               if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
873 +               if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
874                     && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
875                                  struct ip_conntrack_expect *, newtuple, &expect->mask)) {
876                         /* Force NAT to find an unused tuple */
877 diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_core.c.orig linux/net/ipv4/netfilter/ip_conntrack_core.c.orig
878 --- linux_org/net/ipv4/netfilter/ip_conntrack_core.c.orig       1970-01-01 01:00:00.000000000 +0100
879 +++ linux/net/ipv4/netfilter/ip_conntrack_core.c.orig   2004-11-24 12:14:04.000000000 +0100
880 @@ -0,0 +1,1446 @@
881 +/* Connection state tracking for netfilter.  This is separated from,
882 +   but required by, the NAT layer; it can also be used by an iptables
883 +   extension. */
884 +
885 +/* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
886 + * Public Licence. 
887 + *
888 + * 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
889 + *     - new API and handling of conntrack/nat helpers
890 + *     - now capable of multiple expectations for one master
891 + * 16 Jul 2002: Harald Welte <laforge@gnumonks.org>
892 + *     - add usage/reference counts to ip_conntrack_expect
893 + *     - export ip_conntrack[_expect]_{find_get,put} functions
894 + * */
895 +
896 +#include <linux/version.h>
897 +#include <linux/config.h>
898 +#include <linux/types.h>
899 +#include <linux/ip.h>
900 +#include <linux/netfilter.h>
901 +#include <linux/netfilter_ipv4.h>
902 +#include <linux/module.h>
903 +#include <linux/skbuff.h>
904 +#include <linux/proc_fs.h>
905 +#include <linux/vmalloc.h>
906 +#include <linux/brlock.h>
907 +#include <net/checksum.h>
908 +#include <linux/stddef.h>
909 +#include <linux/sysctl.h>
910 +#include <linux/slab.h>
911 +#include <linux/random.h>
912 +#include <linux/jhash.h>
913 +/* For ERR_PTR().  Yeah, I know... --RR */
914 +#include <linux/fs.h>
915 +
916 +/* This rwlock protects the main hash table, protocol/helper/expected
917 +   registrations, conntrack timers*/
918 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
919 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_conntrack_lock)
920 +
921 +#include <linux/netfilter_ipv4/ip_conntrack.h>
922 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
923 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
924 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
925 +#include <linux/netfilter_ipv4/listhelp.h>
926 +
927 +#define IP_CONNTRACK_VERSION   "2.1"
928 +
929 +#if 0
930 +#define DEBUGP printk
931 +#else
932 +#define DEBUGP(format, args...)
933 +#endif
934 +
935 +DECLARE_RWLOCK(ip_conntrack_lock);
936 +DECLARE_RWLOCK(ip_conntrack_expect_tuple_lock);
937 +
938 +void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack) = NULL;
939 +LIST_HEAD(ip_conntrack_expect_list);
940 +LIST_HEAD(protocol_list);
941 +static LIST_HEAD(helpers);
942 +unsigned int ip_conntrack_htable_size = 0;
943 +int ip_conntrack_max = 0;
944 +static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
945 +struct list_head *ip_conntrack_hash;
946 +static kmem_cache_t *ip_conntrack_cachep;
947 +
948 +extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
949 +
950 +static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr,
951 +                             u_int8_t protocol)
952 +{
953 +       return protocol == curr->proto;
954 +}
955 +
956 +struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
957 +{
958 +       struct ip_conntrack_protocol *p;
959 +
960 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
961 +       p = LIST_FIND(&protocol_list, proto_cmpfn,
962 +                     struct ip_conntrack_protocol *, protocol);
963 +       if (!p)
964 +               p = &ip_conntrack_generic_protocol;
965 +
966 +       return p;
967 +}
968 +
969 +struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol)
970 +{
971 +       struct ip_conntrack_protocol *p;
972 +
973 +       READ_LOCK(&ip_conntrack_lock);
974 +       p = __ip_ct_find_proto(protocol);
975 +       READ_UNLOCK(&ip_conntrack_lock);
976 +       return p;
977 +}
978 +
979 +inline void 
980 +ip_conntrack_put(struct ip_conntrack *ct)
981 +{
982 +       IP_NF_ASSERT(ct);
983 +       IP_NF_ASSERT(ct->infos[0].master);
984 +       /* nf_conntrack_put wants to go via an info struct, so feed it
985 +           one at random. */
986 +       nf_conntrack_put(&ct->infos[0]);
987 +}
988 +
989 +static int ip_conntrack_hash_rnd_initted;
990 +static unsigned int ip_conntrack_hash_rnd;
991 +
992 +static u_int32_t
993 +hash_conntrack(const struct ip_conntrack_tuple *tuple)
994 +{
995 +#if 0
996 +       dump_tuple(tuple);
997 +#endif
998 +       return (jhash_3words(tuple->src.ip,
999 +                            (tuple->dst.ip ^ tuple->dst.protonum),
1000 +                            (tuple->src.u.all | (tuple->dst.u.all << 16)),
1001 +                            ip_conntrack_hash_rnd) % ip_conntrack_htable_size);
1002 +}
1003 +
1004 +inline int
1005 +get_tuple(const struct iphdr *iph, size_t len,
1006 +         struct ip_conntrack_tuple *tuple,
1007 +         struct ip_conntrack_protocol *protocol)
1008 +{
1009 +       int ret;
1010 +
1011 +       /* Never happen */
1012 +       if (iph->frag_off & htons(IP_OFFSET)) {
1013 +               printk("ip_conntrack_core: Frag of proto %u.\n",
1014 +                      iph->protocol);
1015 +               return 0;
1016 +       }
1017 +       /* Guarantee 8 protocol bytes: if more wanted, use len param */
1018 +       else if (iph->ihl * 4 + 8 > len)
1019 +               return 0;
1020 +
1021 +       tuple->src.ip = iph->saddr;
1022 +       tuple->dst.ip = iph->daddr;
1023 +       tuple->dst.protonum = iph->protocol;
1024 +
1025 +       ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
1026 +                                    len - 4*iph->ihl,
1027 +                                    tuple);
1028 +       return ret;
1029 +}
1030 +
1031 +static int
1032 +invert_tuple(struct ip_conntrack_tuple *inverse,
1033 +            const struct ip_conntrack_tuple *orig,
1034 +            const struct ip_conntrack_protocol *protocol)
1035 +{
1036 +       inverse->src.ip = orig->dst.ip;
1037 +       inverse->dst.ip = orig->src.ip;
1038 +       inverse->dst.protonum = orig->dst.protonum;
1039 +
1040 +       return protocol->invert_tuple(inverse, orig);
1041 +}
1042 +
1043 +
1044 +/* ip_conntrack_expect helper functions */
1045 +
1046 +/* Compare tuple parts depending on mask. */
1047 +static inline int expect_cmp(const struct ip_conntrack_expect *i,
1048 +                            const struct ip_conntrack_tuple *tuple)
1049 +{
1050 +       MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1051 +       return ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask);
1052 +}
1053 +
1054 +static void
1055 +destroy_expect(struct ip_conntrack_expect *exp)
1056 +{
1057 +       DEBUGP("destroy_expect(%p) use=%d\n", exp, atomic_read(&exp->use));
1058 +       IP_NF_ASSERT(atomic_read(&exp->use) == 0);
1059 +       IP_NF_ASSERT(!timer_pending(&exp->timeout));
1060 +
1061 +       kfree(exp);
1062 +}
1063 +
1064 +inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp)
1065 +{
1066 +       IP_NF_ASSERT(exp);
1067 +
1068 +       if (atomic_dec_and_test(&exp->use)) {
1069 +               /* usage count dropped to zero */
1070 +               destroy_expect(exp);
1071 +       }
1072 +}
1073 +
1074 +static inline struct ip_conntrack_expect *
1075 +__ip_ct_expect_find(const struct ip_conntrack_tuple *tuple)
1076 +{
1077 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1078 +       MUST_BE_READ_LOCKED(&ip_conntrack_expect_tuple_lock);
1079 +       return LIST_FIND(&ip_conntrack_expect_list, expect_cmp, 
1080 +                        struct ip_conntrack_expect *, tuple);
1081 +}
1082 +
1083 +/* Find a expectation corresponding to a tuple. */
1084 +struct ip_conntrack_expect *
1085 +ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
1086 +{
1087 +       struct ip_conntrack_expect *exp;
1088 +
1089 +       READ_LOCK(&ip_conntrack_lock);
1090 +       READ_LOCK(&ip_conntrack_expect_tuple_lock);
1091 +       exp = __ip_ct_expect_find(tuple);
1092 +       if (exp)
1093 +               atomic_inc(&exp->use);
1094 +       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1095 +       READ_UNLOCK(&ip_conntrack_lock);
1096 +
1097 +       return exp;
1098 +}
1099 +
1100 +/* remove one specific expectation from all lists and drop refcount,
1101 + * does _NOT_ delete the timer. */
1102 +static void __unexpect_related(struct ip_conntrack_expect *expect)
1103 +{
1104 +       DEBUGP("unexpect_related(%p)\n", expect);
1105 +       MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1106 +
1107 +       /* we're not allowed to unexpect a confirmed expectation! */
1108 +       IP_NF_ASSERT(!expect->sibling);
1109 +
1110 +       /* delete from global and local lists */
1111 +       list_del(&expect->list);
1112 +       list_del(&expect->expected_list);
1113 +
1114 +       /* decrement expect-count of master conntrack */
1115 +       if (expect->expectant)
1116 +               expect->expectant->expecting--;
1117 +
1118 +       ip_conntrack_expect_put(expect);
1119 +}
1120 +
1121 +/* remove one specific expecatation from all lists, drop refcount
1122 + * and expire timer. 
1123 + * This function can _NOT_ be called for confirmed expects! */
1124 +static void unexpect_related(struct ip_conntrack_expect *expect)
1125 +{
1126 +       IP_NF_ASSERT(expect->expectant);
1127 +       IP_NF_ASSERT(expect->expectant->helper);
1128 +       /* if we are supposed to have a timer, but we can't delete
1129 +        * it: race condition.  __unexpect_related will
1130 +        * be calledd by timeout function */
1131 +       if (expect->expectant->helper->timeout
1132 +           && !del_timer(&expect->timeout))
1133 +               return;
1134 +
1135 +       __unexpect_related(expect);
1136 +}
1137 +
1138 +/* delete all unconfirmed expectations for this conntrack */
1139 +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
1140 +{
1141 +       struct list_head *exp_entry, *next;
1142 +       struct ip_conntrack_expect *exp;
1143 +
1144 +       DEBUGP("remove_expectations(%p)\n", ct);
1145 +
1146 +       list_for_each_safe(exp_entry, next, &ct->sibling_list) {
1147 +               exp = list_entry(exp_entry, struct ip_conntrack_expect,
1148 +                                expected_list);
1149 +
1150 +               /* we skip established expectations, as we want to delete
1151 +                * the un-established ones only */
1152 +               if (exp->sibling) {
1153 +                       DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
1154 +                       if (drop_refcount) {
1155 +                               /* Indicate that this expectations parent is dead */
1156 +                               ip_conntrack_put(exp->expectant);
1157 +                               exp->expectant = NULL;
1158 +                       }
1159 +                       continue;
1160 +               }
1161 +
1162 +               IP_NF_ASSERT(list_inlist(&ip_conntrack_expect_list, exp));
1163 +               IP_NF_ASSERT(exp->expectant == ct);
1164 +
1165 +               /* delete expectation from global and private lists */
1166 +               unexpect_related(exp);
1167 +       }
1168 +}
1169 +
1170 +static void
1171 +clean_from_lists(struct ip_conntrack *ct)
1172 +{
1173 +       unsigned int ho, hr;
1174 +       
1175 +       DEBUGP("clean_from_lists(%p)\n", ct);
1176 +       MUST_BE_WRITE_LOCKED(&ip_conntrack_lock);
1177 +
1178 +       ho = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1179 +       hr = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
1180 +       LIST_DELETE(&ip_conntrack_hash[ho], &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
1181 +       LIST_DELETE(&ip_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]);
1182 +
1183 +       /* Destroy all un-established, pending expectations */
1184 +       remove_expectations(ct, 1);
1185 +}
1186 +
1187 +static void
1188 +destroy_conntrack(struct nf_conntrack *nfct)
1189 +{
1190 +       struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
1191 +       struct ip_conntrack_protocol *proto;
1192 +
1193 +       DEBUGP("destroy_conntrack(%p)\n", ct);
1194 +       IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
1195 +       IP_NF_ASSERT(!timer_pending(&ct->timeout));
1196 +
1197 +       /* To make sure we don't get any weird locking issues here:
1198 +        * destroy_conntrack() MUST NOT be called with a write lock
1199 +        * to ip_conntrack_lock!!! -HW */
1200 +       proto = ip_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
1201 +       if (proto && proto->destroy)
1202 +               proto->destroy(ct);
1203 +
1204 +       if (ip_conntrack_destroyed)
1205 +               ip_conntrack_destroyed(ct);
1206 +
1207 +       WRITE_LOCK(&ip_conntrack_lock);
1208 +       /* Make sure don't leave any orphaned expectations lying around */
1209 +       if (ct->expecting)
1210 +               remove_expectations(ct, 1);
1211 +
1212 +       /* Delete our master expectation */
1213 +       if (ct->master) {
1214 +               if (ct->master->expectant) {
1215 +                       /* can't call __unexpect_related here,
1216 +                        * since it would screw up expect_list */
1217 +                       list_del(&ct->master->expected_list);
1218 +                       master = ct->master->expectant;
1219 +               }
1220 +               kfree(ct->master);
1221 +       }
1222 +       WRITE_UNLOCK(&ip_conntrack_lock);
1223 +
1224 +       if (master)
1225 +               ip_conntrack_put(master);
1226 +
1227 +       DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
1228 +       kmem_cache_free(ip_conntrack_cachep, ct);
1229 +       atomic_dec(&ip_conntrack_count);
1230 +}
1231 +
1232 +static void death_by_timeout(unsigned long ul_conntrack)
1233 +{
1234 +       struct ip_conntrack *ct = (void *)ul_conntrack;
1235 +
1236 +       WRITE_LOCK(&ip_conntrack_lock);
1237 +       clean_from_lists(ct);
1238 +       WRITE_UNLOCK(&ip_conntrack_lock);
1239 +       ip_conntrack_put(ct);
1240 +}
1241 +
1242 +static inline int
1243 +conntrack_tuple_cmp(const struct ip_conntrack_tuple_hash *i,
1244 +                   const struct ip_conntrack_tuple *tuple,
1245 +                   const struct ip_conntrack *ignored_conntrack)
1246 +{
1247 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1248 +       return i->ctrack != ignored_conntrack
1249 +               && ip_ct_tuple_equal(tuple, &i->tuple);
1250 +}
1251 +
1252 +static struct ip_conntrack_tuple_hash *
1253 +__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
1254 +                   const struct ip_conntrack *ignored_conntrack)
1255 +{
1256 +       struct ip_conntrack_tuple_hash *h;
1257 +       unsigned int hash = hash_conntrack(tuple);
1258 +
1259 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1260 +       h = LIST_FIND(&ip_conntrack_hash[hash],
1261 +                     conntrack_tuple_cmp,
1262 +                     struct ip_conntrack_tuple_hash *,
1263 +                     tuple, ignored_conntrack);
1264 +       return h;
1265 +}
1266 +
1267 +/* Find a connection corresponding to a tuple. */
1268 +struct ip_conntrack_tuple_hash *
1269 +ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
1270 +                     const struct ip_conntrack *ignored_conntrack)
1271 +{
1272 +       struct ip_conntrack_tuple_hash *h;
1273 +
1274 +       READ_LOCK(&ip_conntrack_lock);
1275 +       h = __ip_conntrack_find(tuple, ignored_conntrack);
1276 +       if (h)
1277 +               atomic_inc(&h->ctrack->ct_general.use);
1278 +       READ_UNLOCK(&ip_conntrack_lock);
1279 +
1280 +       return h;
1281 +}
1282 +
1283 +static inline struct ip_conntrack *
1284 +__ip_conntrack_get(struct nf_ct_info *nfct, enum ip_conntrack_info *ctinfo)
1285 +{
1286 +       struct ip_conntrack *ct
1287 +               = (struct ip_conntrack *)nfct->master;
1288 +
1289 +       /* ctinfo is the index of the nfct inside the conntrack */
1290 +       *ctinfo = nfct - ct->infos;
1291 +       IP_NF_ASSERT(*ctinfo >= 0 && *ctinfo < IP_CT_NUMBER);
1292 +       return ct;
1293 +}
1294 +
1295 +/* Return conntrack and conntrack_info given skb->nfct->master */
1296 +struct ip_conntrack *
1297 +ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
1298 +{
1299 +       if (skb->nfct) 
1300 +               return __ip_conntrack_get(skb->nfct, ctinfo);
1301 +       return NULL;
1302 +}
1303 +
1304 +/* Confirm a connection given skb->nfct; places it in hash table */
1305 +int
1306 +__ip_conntrack_confirm(struct nf_ct_info *nfct)
1307 +{
1308 +       unsigned int hash, repl_hash;
1309 +       struct ip_conntrack *ct;
1310 +       enum ip_conntrack_info ctinfo;
1311 +
1312 +       ct = __ip_conntrack_get(nfct, &ctinfo);
1313 +
1314 +       /* ipt_REJECT uses ip_conntrack_attach to attach related
1315 +          ICMP/TCP RST packets in other direction.  Actual packet
1316 +          which created connection will be IP_CT_NEW or for an
1317 +          expected connection, IP_CT_RELATED. */
1318 +       if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
1319 +               return NF_ACCEPT;
1320 +
1321 +       hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1322 +       repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
1323 +
1324 +       /* We're not in hash table, and we refuse to set up related
1325 +          connections for unconfirmed conns.  But packet copies and
1326 +          REJECT will give spurious warnings here. */
1327 +       /* IP_NF_ASSERT(atomic_read(&ct->ct_general.use) == 1); */
1328 +
1329 +       /* No external references means noone else could have
1330 +           confirmed us. */
1331 +       IP_NF_ASSERT(!is_confirmed(ct));
1332 +       DEBUGP("Confirming conntrack %p\n", ct);
1333 +
1334 +       WRITE_LOCK(&ip_conntrack_lock);
1335 +       /* See if there's one in the list already, including reverse:
1336 +           NAT could have grabbed it without realizing, since we're
1337 +           not in the hash.  If there is, we lost race. */
1338 +       if (!LIST_FIND(&ip_conntrack_hash[hash],
1339 +                      conntrack_tuple_cmp,
1340 +                      struct ip_conntrack_tuple_hash *,
1341 +                      &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, NULL)
1342 +           && !LIST_FIND(&ip_conntrack_hash[repl_hash],
1343 +                         conntrack_tuple_cmp,
1344 +                         struct ip_conntrack_tuple_hash *,
1345 +                         &ct->tuplehash[IP_CT_DIR_REPLY].tuple, NULL)) {
1346 +               list_prepend(&ip_conntrack_hash[hash],
1347 +                            &ct->tuplehash[IP_CT_DIR_ORIGINAL]);
1348 +               list_prepend(&ip_conntrack_hash[repl_hash],
1349 +                            &ct->tuplehash[IP_CT_DIR_REPLY]);
1350 +               /* Timer relative to confirmation time, not original
1351 +                  setting time, otherwise we'd get timer wrap in
1352 +                  weird delay cases. */
1353 +               ct->timeout.expires += jiffies;
1354 +               add_timer(&ct->timeout);
1355 +               atomic_inc(&ct->ct_general.use);
1356 +               set_bit(IPS_CONFIRMED_BIT, &ct->status);
1357 +               WRITE_UNLOCK(&ip_conntrack_lock);
1358 +               return NF_ACCEPT;
1359 +       }
1360 +
1361 +       WRITE_UNLOCK(&ip_conntrack_lock);
1362 +       return NF_DROP;
1363 +}
1364 +
1365 +/* Returns true if a connection correspondings to the tuple (required
1366 +   for NAT). */
1367 +int
1368 +ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
1369 +                        const struct ip_conntrack *ignored_conntrack)
1370 +{
1371 +       struct ip_conntrack_tuple_hash *h;
1372 +
1373 +       READ_LOCK(&ip_conntrack_lock);
1374 +       h = __ip_conntrack_find(tuple, ignored_conntrack);
1375 +       READ_UNLOCK(&ip_conntrack_lock);
1376 +
1377 +       return h != NULL;
1378 +}
1379 +
1380 +/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
1381 +struct ip_conntrack *
1382 +icmp_error_track(struct sk_buff *skb,
1383 +                enum ip_conntrack_info *ctinfo,
1384 +                unsigned int hooknum)
1385 +{
1386 +       const struct iphdr *iph = skb->nh.iph;
1387 +       struct icmphdr *hdr;
1388 +       struct ip_conntrack_tuple innertuple, origtuple;
1389 +       struct iphdr *inner;
1390 +       size_t datalen;
1391 +       struct ip_conntrack_protocol *innerproto;
1392 +       struct ip_conntrack_tuple_hash *h;
1393 +
1394 +       IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);
1395 +       IP_NF_ASSERT(skb->nfct == NULL);
1396 +
1397 +       hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
1398 +       inner = (struct iphdr *)(hdr + 1);
1399 +       datalen = skb->len - iph->ihl*4 - sizeof(*hdr);
1400 +
1401 +       if (skb->len < iph->ihl * 4 + sizeof(*hdr) + sizeof(*iph)) {
1402 +               DEBUGP("icmp_error_track: too short\n");
1403 +               return NULL;
1404 +       }
1405 +
1406 +       if (hdr->type != ICMP_DEST_UNREACH
1407 +           && hdr->type != ICMP_SOURCE_QUENCH
1408 +           && hdr->type != ICMP_TIME_EXCEEDED
1409 +           && hdr->type != ICMP_PARAMETERPROB
1410 +           && hdr->type != ICMP_REDIRECT)
1411 +               return NULL;
1412 +
1413 +       /* Ignore ICMP's containing fragments (shouldn't happen) */
1414 +       if (inner->frag_off & htons(IP_OFFSET)) {
1415 +               DEBUGP("icmp_error_track: fragment of proto %u\n",
1416 +                      inner->protocol);
1417 +               return NULL;
1418 +       }
1419 +
1420 +       /* Ignore it if the checksum's bogus. */
1421 +       if (ip_compute_csum((unsigned char *)hdr, sizeof(*hdr) + datalen)) {
1422 +               DEBUGP("icmp_error_track: bad csum\n");
1423 +               return NULL;
1424 +       }
1425 +
1426 +       innerproto = ip_ct_find_proto(inner->protocol);
1427 +       /* Are they talking about one of our connections? */
1428 +       if (inner->ihl * 4 + 8 > datalen
1429 +           || !get_tuple(inner, datalen, &origtuple, innerproto)) {
1430 +               DEBUGP("icmp_error: ! get_tuple p=%u (%u*4+%u dlen=%u)\n",
1431 +                      inner->protocol, inner->ihl, 8,
1432 +                      datalen);
1433 +               return NULL;
1434 +       }
1435 +
1436 +       /* Ordinarily, we'd expect the inverted tupleproto, but it's
1437 +          been preserved inside the ICMP. */
1438 +       if (!invert_tuple(&innertuple, &origtuple, innerproto)) {
1439 +               DEBUGP("icmp_error_track: Can't invert tuple\n");
1440 +               return NULL;
1441 +       }
1442 +
1443 +       *ctinfo = IP_CT_RELATED;
1444 +
1445 +       h = ip_conntrack_find_get(&innertuple, NULL);
1446 +       if (!h) {
1447 +               /* Locally generated ICMPs will match inverted if they
1448 +                  haven't been SNAT'ed yet */
1449 +               /* FIXME: NAT code has to handle half-done double NAT --RR */
1450 +               if (hooknum == NF_IP_LOCAL_OUT)
1451 +                       h = ip_conntrack_find_get(&origtuple, NULL);
1452 +
1453 +               if (!h) {
1454 +                       DEBUGP("icmp_error_track: no match\n");
1455 +                       return NULL;
1456 +               }
1457 +               /* Reverse direction from that found */
1458 +               if (DIRECTION(h) != IP_CT_DIR_REPLY)
1459 +                       *ctinfo += IP_CT_IS_REPLY;
1460 +       } else {
1461 +               if (DIRECTION(h) == IP_CT_DIR_REPLY)
1462 +                       *ctinfo += IP_CT_IS_REPLY;
1463 +       }
1464 +
1465 +       /* Update skb to refer to this connection */
1466 +       skb->nfct = &h->ctrack->infos[*ctinfo];
1467 +       return h->ctrack;
1468 +}
1469 +
1470 +/* There's a small race here where we may free a just-assured
1471 +   connection.  Too bad: we're in trouble anyway. */
1472 +static inline int unreplied(const struct ip_conntrack_tuple_hash *i)
1473 +{
1474 +       return !(test_bit(IPS_ASSURED_BIT, &i->ctrack->status));
1475 +}
1476 +
1477 +static int early_drop(struct list_head *chain)
1478 +{
1479 +       /* Traverse backwards: gives us oldest, which is roughly LRU */
1480 +       struct ip_conntrack_tuple_hash *h;
1481 +       int dropped = 0;
1482 +
1483 +       READ_LOCK(&ip_conntrack_lock);
1484 +       h = LIST_FIND_B(chain, unreplied, struct ip_conntrack_tuple_hash *);
1485 +       if (h)
1486 +               atomic_inc(&h->ctrack->ct_general.use);
1487 +       READ_UNLOCK(&ip_conntrack_lock);
1488 +
1489 +       if (!h)
1490 +               return dropped;
1491 +
1492 +       if (del_timer(&h->ctrack->timeout)) {
1493 +               death_by_timeout((unsigned long)h->ctrack);
1494 +               dropped = 1;
1495 +       }
1496 +       ip_conntrack_put(h->ctrack);
1497 +       return dropped;
1498 +}
1499 +
1500 +static inline int helper_cmp(const struct ip_conntrack_helper *i,
1501 +                            const struct ip_conntrack_tuple *rtuple)
1502 +{
1503 +       return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask);
1504 +}
1505 +
1506 +struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple)
1507 +{
1508 +       return LIST_FIND(&helpers, helper_cmp,
1509 +                        struct ip_conntrack_helper *,
1510 +                        tuple);
1511 +}
1512 +
1513 +/* Allocate a new conntrack: we return -ENOMEM if classification
1514 +   failed due to stress.  Otherwise it really is unclassifiable. */
1515 +static struct ip_conntrack_tuple_hash *
1516 +init_conntrack(const struct ip_conntrack_tuple *tuple,
1517 +              struct ip_conntrack_protocol *protocol,
1518 +              struct sk_buff *skb)
1519 +{
1520 +       struct ip_conntrack *conntrack;
1521 +       struct ip_conntrack_tuple repl_tuple;
1522 +       size_t hash;
1523 +       struct ip_conntrack_expect *expected;
1524 +       int i;
1525 +       static unsigned int drop_next = 0;
1526 +
1527 +       if (!ip_conntrack_hash_rnd_initted) {
1528 +               get_random_bytes(&ip_conntrack_hash_rnd, 4);
1529 +               ip_conntrack_hash_rnd_initted = 1;
1530 +       }
1531 +
1532 +       hash = hash_conntrack(tuple);
1533 +
1534 +       if (ip_conntrack_max &&
1535 +           atomic_read(&ip_conntrack_count) >= ip_conntrack_max) {
1536 +               /* Try dropping from random chain, or else from the
1537 +                   chain about to put into (in case they're trying to
1538 +                   bomb one hash chain). */
1539 +               unsigned int next = (drop_next++)%ip_conntrack_htable_size;
1540 +
1541 +               if (!early_drop(&ip_conntrack_hash[next])
1542 +                   && !early_drop(&ip_conntrack_hash[hash])) {
1543 +                       if (net_ratelimit())
1544 +                               printk(KERN_WARNING
1545 +                                      "ip_conntrack: table full, dropping"
1546 +                                      " packet.\n");
1547 +                       return ERR_PTR(-ENOMEM);
1548 +               }
1549 +       }
1550 +
1551 +       if (!invert_tuple(&repl_tuple, tuple, protocol)) {
1552 +               DEBUGP("Can't invert tuple.\n");
1553 +               return NULL;
1554 +       }
1555 +
1556 +       conntrack = kmem_cache_alloc(ip_conntrack_cachep, GFP_ATOMIC);
1557 +       if (!conntrack) {
1558 +               DEBUGP("Can't allocate conntrack.\n");
1559 +               return ERR_PTR(-ENOMEM);
1560 +       }
1561 +
1562 +       memset(conntrack, 0, sizeof(*conntrack));
1563 +       atomic_set(&conntrack->ct_general.use, 1);
1564 +       conntrack->ct_general.destroy = destroy_conntrack;
1565 +       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *tuple;
1566 +       conntrack->tuplehash[IP_CT_DIR_ORIGINAL].ctrack = conntrack;
1567 +       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = repl_tuple;
1568 +       conntrack->tuplehash[IP_CT_DIR_REPLY].ctrack = conntrack;
1569 +       for (i=0; i < IP_CT_NUMBER; i++)
1570 +               conntrack->infos[i].master = &conntrack->ct_general;
1571 +
1572 +       if (!protocol->new(conntrack, skb->nh.iph, skb->len)) {
1573 +               kmem_cache_free(ip_conntrack_cachep, conntrack);
1574 +               return NULL;
1575 +       }
1576 +       /* Don't set timer yet: wait for confirmation */
1577 +       init_timer(&conntrack->timeout);
1578 +       conntrack->timeout.data = (unsigned long)conntrack;
1579 +       conntrack->timeout.function = death_by_timeout;
1580 +
1581 +       INIT_LIST_HEAD(&conntrack->sibling_list);
1582 +
1583 +       WRITE_LOCK(&ip_conntrack_lock);
1584 +       /* Need finding and deleting of expected ONLY if we win race */
1585 +       READ_LOCK(&ip_conntrack_expect_tuple_lock);
1586 +       expected = LIST_FIND(&ip_conntrack_expect_list, expect_cmp,
1587 +                            struct ip_conntrack_expect *, tuple);
1588 +       READ_UNLOCK(&ip_conntrack_expect_tuple_lock);
1589 +
1590 +       /* If master is not in hash table yet (ie. packet hasn't left
1591 +          this machine yet), how can other end know about expected?
1592 +          Hence these are not the droids you are looking for (if
1593 +          master ct never got confirmed, we'd hold a reference to it
1594 +          and weird things would happen to future packets). */
1595 +       if (expected && !is_confirmed(expected->expectant))
1596 +               expected = NULL;
1597 +
1598 +       /* Look up the conntrack helper for master connections only */
1599 +       if (!expected)
1600 +               conntrack->helper = ip_ct_find_helper(&repl_tuple);
1601 +
1602 +       /* If the expectation is dying, then this is a looser. */
1603 +       if (expected
1604 +           && expected->expectant->helper->timeout
1605 +           && ! del_timer(&expected->timeout))
1606 +               expected = NULL;
1607 +
1608 +       if (expected) {
1609 +               DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
1610 +                       conntrack, expected);
1611 +               /* Welcome, Mr. Bond.  We've been expecting you... */
1612 +               __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
1613 +               conntrack->master = expected;
1614 +               expected->sibling = conntrack;
1615 +               LIST_DELETE(&ip_conntrack_expect_list, expected);
1616 +               expected->expectant->expecting--;
1617 +               nf_conntrack_get(&master_ct(conntrack)->infos[0]);
1618 +       }
1619 +       atomic_inc(&ip_conntrack_count);
1620 +       WRITE_UNLOCK(&ip_conntrack_lock);
1621 +
1622 +       if (expected && expected->expectfn)
1623 +               expected->expectfn(conntrack);
1624 +       return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
1625 +}
1626 +
1627 +/* On success, returns conntrack ptr, sets skb->nfct and ctinfo */
1628 +static inline struct ip_conntrack *
1629 +resolve_normal_ct(struct sk_buff *skb,
1630 +                 struct ip_conntrack_protocol *proto,
1631 +                 int *set_reply,
1632 +                 unsigned int hooknum,
1633 +                 enum ip_conntrack_info *ctinfo)
1634 +{
1635 +       struct ip_conntrack_tuple tuple;
1636 +       struct ip_conntrack_tuple_hash *h;
1637 +
1638 +       IP_NF_ASSERT((skb->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
1639 +
1640 +       if (!get_tuple(skb->nh.iph, skb->len, &tuple, proto))
1641 +               return NULL;
1642 +
1643 +       /* look for tuple match */
1644 +       h = ip_conntrack_find_get(&tuple, NULL);
1645 +       if (!h) {
1646 +               h = init_conntrack(&tuple, proto, skb);
1647 +               if (!h)
1648 +                       return NULL;
1649 +               if (IS_ERR(h))
1650 +                       return (void *)h;
1651 +       }
1652 +
1653 +       /* It exists; we have (non-exclusive) reference. */
1654 +       if (DIRECTION(h) == IP_CT_DIR_REPLY) {
1655 +               *ctinfo = IP_CT_ESTABLISHED + IP_CT_IS_REPLY;
1656 +               /* Please set reply bit if this packet OK */
1657 +               *set_reply = 1;
1658 +       } else {
1659 +               /* Once we've had two way comms, always ESTABLISHED. */
1660 +               if (test_bit(IPS_SEEN_REPLY_BIT, &h->ctrack->status)) {
1661 +                       DEBUGP("ip_conntrack_in: normal packet for %p\n",
1662 +                              h->ctrack);
1663 +                       *ctinfo = IP_CT_ESTABLISHED;
1664 +               } else if (test_bit(IPS_EXPECTED_BIT, &h->ctrack->status)) {
1665 +                       DEBUGP("ip_conntrack_in: related packet for %p\n",
1666 +                              h->ctrack);
1667 +                       *ctinfo = IP_CT_RELATED;
1668 +               } else {
1669 +                       DEBUGP("ip_conntrack_in: new packet for %p\n",
1670 +                              h->ctrack);
1671 +                       *ctinfo = IP_CT_NEW;
1672 +               }
1673 +               *set_reply = 0;
1674 +       }
1675 +       skb->nfct = &h->ctrack->infos[*ctinfo];
1676 +       return h->ctrack;
1677 +}
1678 +
1679 +/* Netfilter hook itself. */
1680 +unsigned int ip_conntrack_in(unsigned int hooknum,
1681 +                            struct sk_buff **pskb,
1682 +                            const struct net_device *in,
1683 +                            const struct net_device *out,
1684 +                            int (*okfn)(struct sk_buff *))
1685 +{
1686 +       struct ip_conntrack *ct;
1687 +       enum ip_conntrack_info ctinfo;
1688 +       struct ip_conntrack_protocol *proto;
1689 +       int set_reply;
1690 +       int ret;
1691 +
1692 +       /* FIXME: Do this right please. --RR */
1693 +       (*pskb)->nfcache |= NFC_UNKNOWN;
1694 +
1695 +/* Doesn't cover locally-generated broadcast, so not worth it. */
1696 +#if 0
1697 +       /* Ignore broadcast: no `connection'. */
1698 +       if ((*pskb)->pkt_type == PACKET_BROADCAST) {
1699 +               printk("Broadcast packet!\n");
1700 +               return NF_ACCEPT;
1701 +       } else if (((*pskb)->nh.iph->daddr & htonl(0x000000FF)) 
1702 +                  == htonl(0x000000FF)) {
1703 +               printk("Should bcast: %u.%u.%u.%u->%u.%u.%u.%u (sk=%p, ptype=%u)\n",
1704 +                      NIPQUAD((*pskb)->nh.iph->saddr),
1705 +                      NIPQUAD((*pskb)->nh.iph->daddr),
1706 +                      (*pskb)->sk, (*pskb)->pkt_type);
1707 +       }
1708 +#endif
1709 +
1710 +       /* Previously seen (loopback)?  Ignore.  Do this before
1711 +           fragment check. */
1712 +       if ((*pskb)->nfct)
1713 +               return NF_ACCEPT;
1714 +
1715 +       /* Gather fragments. */
1716 +       if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
1717 +               *pskb = ip_ct_gather_frags(*pskb);
1718 +               if (!*pskb)
1719 +                       return NF_STOLEN;
1720 +       }
1721 +
1722 +       proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
1723 +
1724 +       /* It may be an icmp error... */
1725 +       if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP 
1726 +           && icmp_error_track(*pskb, &ctinfo, hooknum))
1727 +               return NF_ACCEPT;
1728 +
1729 +       if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo)))
1730 +               /* Not valid part of a connection */
1731 +               return NF_ACCEPT;
1732 +
1733 +       if (IS_ERR(ct))
1734 +               /* Too stressed to deal. */
1735 +               return NF_DROP;
1736 +
1737 +       IP_NF_ASSERT((*pskb)->nfct);
1738 +
1739 +       ret = proto->packet(ct, (*pskb)->nh.iph, (*pskb)->len, ctinfo);
1740 +       if (ret == -1) {
1741 +               /* Invalid */
1742 +               nf_conntrack_put((*pskb)->nfct);
1743 +               (*pskb)->nfct = NULL;
1744 +               return NF_ACCEPT;
1745 +       }
1746 +
1747 +       if (ret != NF_DROP && ct->helper) {
1748 +               ret = ct->helper->help((*pskb)->nh.iph, (*pskb)->len,
1749 +                                      ct, ctinfo);
1750 +               if (ret == -1) {
1751 +                       /* Invalid */
1752 +                       nf_conntrack_put((*pskb)->nfct);
1753 +                       (*pskb)->nfct = NULL;
1754 +                       return NF_ACCEPT;
1755 +               }
1756 +       }
1757 +       if (set_reply)
1758 +               set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
1759 +
1760 +       return ret;
1761 +}
1762 +
1763 +int invert_tuplepr(struct ip_conntrack_tuple *inverse,
1764 +                  const struct ip_conntrack_tuple *orig)
1765 +{
1766 +       return invert_tuple(inverse, orig, ip_ct_find_proto(orig->dst.protonum));
1767 +}
1768 +
1769 +static inline int resent_expect(const struct ip_conntrack_expect *i,
1770 +                               const struct ip_conntrack_tuple *tuple,
1771 +                               const struct ip_conntrack_tuple *mask)
1772 +{
1773 +       DEBUGP("resent_expect\n");
1774 +       DEBUGP("   tuple:   "); DUMP_TUPLE(&i->tuple);
1775 +       DEBUGP("ct_tuple:   "); DUMP_TUPLE(&i->ct_tuple);
1776 +       DEBUGP("test tuple: "); DUMP_TUPLE(tuple);
1777 +       return (((i->ct_tuple.dst.protonum == 0 && ip_ct_tuple_equal(&i->tuple, tuple))
1778 +                || (i->ct_tuple.dst.protonum && ip_ct_tuple_equal(&i->ct_tuple, tuple)))
1779 +               && ip_ct_tuple_equal(&i->mask, mask));
1780 +}
1781 +
1782 +/* Would two expected things clash? */
1783 +static inline int expect_clash(const struct ip_conntrack_expect *i,
1784 +                              const struct ip_conntrack_tuple *tuple,
1785 +                              const struct ip_conntrack_tuple *mask)
1786 +{
1787 +       /* Part covered by intersection of masks must be unequal,
1788 +           otherwise they clash */
1789 +       struct ip_conntrack_tuple intersect_mask
1790 +               = { { i->mask.src.ip & mask->src.ip,
1791 +                     { i->mask.src.u.all & mask->src.u.all } },
1792 +                   { i->mask.dst.ip & mask->dst.ip,
1793 +                     { i->mask.dst.u.all & mask->dst.u.all },
1794 +                     i->mask.dst.protonum & mask->dst.protonum } };
1795 +
1796 +       return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask);
1797 +}
1798 +
1799 +inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect)
1800 +{
1801 +       WRITE_LOCK(&ip_conntrack_lock);
1802 +       unexpect_related(expect);
1803 +       WRITE_UNLOCK(&ip_conntrack_lock);
1804 +}
1805 +       
1806 +static void expectation_timed_out(unsigned long ul_expect)
1807 +{
1808 +       struct ip_conntrack_expect *expect = (void *) ul_expect;
1809 +
1810 +       DEBUGP("expectation %p timed out\n", expect);   
1811 +       WRITE_LOCK(&ip_conntrack_lock);
1812 +       __unexpect_related(expect);
1813 +       WRITE_UNLOCK(&ip_conntrack_lock);
1814 +}
1815 +
1816 +/* Add a related connection. */
1817 +int ip_conntrack_expect_related(struct ip_conntrack *related_to,
1818 +                               struct ip_conntrack_expect *expect)
1819 +{
1820 +       struct ip_conntrack_expect *old, *new;
1821 +       int ret = 0;
1822 +
1823 +       WRITE_LOCK(&ip_conntrack_lock);
1824 +       /* Because of the write lock, no reader can walk the lists,
1825 +        * so there is no need to use the tuple lock too */
1826 +
1827 +       DEBUGP("ip_conntrack_expect_related %p\n", related_to);
1828 +       DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
1829 +       DEBUGP("mask:  "); DUMP_TUPLE(&expect->mask);
1830 +
1831 +       old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
1832 +                       struct ip_conntrack_expect *, &expect->tuple, 
1833 +                       &expect->mask);
1834 +       if (old) {
1835 +               /* Helper private data may contain offsets but no pointers
1836 +                  pointing into the payload - otherwise we should have to copy 
1837 +                  the data filled out by the helper over the old one */
1838 +               DEBUGP("expect_related: resent packet\n");
1839 +               if (related_to->helper->timeout) {
1840 +                       if (!del_timer(&old->timeout)) {
1841 +                               /* expectation is dying. Fall through */
1842 +                               old = NULL;
1843 +                       } else {
1844 +                               old->timeout.expires = jiffies + 
1845 +                                       related_to->helper->timeout * HZ;
1846 +                               add_timer(&old->timeout);
1847 +                       }
1848 +               }
1849 +
1850 +               if (old) {
1851 +                       WRITE_UNLOCK(&ip_conntrack_lock);
1852 +                       return -EEXIST;
1853 +               }
1854 +       } else if (related_to->helper->max_expected && 
1855 +                  related_to->expecting >= related_to->helper->max_expected) {
1856 +               /* old == NULL */
1857 +               if (!(related_to->helper->flags & 
1858 +                     IP_CT_HELPER_F_REUSE_EXPECT)) {
1859 +                       WRITE_UNLOCK(&ip_conntrack_lock);
1860 +                       if (net_ratelimit())
1861 +                               printk(KERN_WARNING
1862 +                                      "ip_conntrack: max number of expected "
1863 +                                      "connections %i of %s reached for "
1864 +                                      "%u.%u.%u.%u->%u.%u.%u.%u\n",
1865 +                                      related_to->helper->max_expected,
1866 +                                      related_to->helper->name,
1867 +                                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
1868 +                                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
1869 +                       return -EPERM;
1870 +               }
1871 +               DEBUGP("ip_conntrack: max number of expected "
1872 +                      "connections %i of %s reached for "
1873 +                      "%u.%u.%u.%u->%u.%u.%u.%u, reusing\n",
1874 +                      related_to->helper->max_expected,
1875 +                      related_to->helper->name,
1876 +                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip),
1877 +                      NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip));
1878
1879 +               /* choose the the oldest expectation to evict */
1880 +               list_for_each_entry(old, &related_to->sibling_list, 
1881 +                                                     expected_list)
1882 +                       if (old->sibling == NULL)
1883 +                               break;
1884 +
1885 +               /* We cannot fail since related_to->expecting is the number
1886 +                * of unconfirmed expectations */
1887 +               IP_NF_ASSERT(old && old->sibling == NULL);
1888 +
1889 +               /* newnat14 does not reuse the real allocated memory
1890 +                * structures but rather unexpects the old and
1891 +                * allocates a new.  unexpect_related will decrement
1892 +                * related_to->expecting. 
1893 +                */
1894 +               unexpect_related(old);
1895 +               ret = -EPERM;
1896 +       } else if (LIST_FIND(&ip_conntrack_expect_list, expect_clash,
1897 +                            struct ip_conntrack_expect *, &expect->tuple, 
1898 +                            &expect->mask)) {
1899 +               WRITE_UNLOCK(&ip_conntrack_lock);
1900 +               DEBUGP("expect_related: busy!\n");
1901 +               return -EBUSY;
1902 +       }
1903 +       
1904 +       new = (struct ip_conntrack_expect *) 
1905 +             kmalloc(sizeof(struct ip_conntrack_expect), GFP_ATOMIC);
1906 +       if (!new) {
1907 +               WRITE_UNLOCK(&ip_conntrack_lock);
1908 +               DEBUGP("expect_relaed: OOM allocating expect\n");
1909 +               return -ENOMEM;
1910 +       }
1911 +       
1912 +       DEBUGP("new expectation %p of conntrack %p\n", new, related_to);
1913 +       memcpy(new, expect, sizeof(*expect));
1914 +       new->expectant = related_to;
1915 +       new->sibling = NULL;
1916 +       atomic_set(&new->use, 1);
1917 +       
1918 +       /* add to expected list for this connection */  
1919 +       list_add_tail(&new->expected_list, &related_to->sibling_list);
1920 +       /* add to global list of expectations */
1921 +       list_prepend(&ip_conntrack_expect_list, &new->list);
1922 +       /* add and start timer if required */
1923 +       if (related_to->helper->timeout) {
1924 +               init_timer(&new->timeout);
1925 +               new->timeout.data = (unsigned long)new;
1926 +               new->timeout.function = expectation_timed_out;
1927 +               new->timeout.expires = jiffies + 
1928 +                                       related_to->helper->timeout * HZ;
1929 +               add_timer(&new->timeout);
1930 +       }
1931 +       related_to->expecting++;
1932 +
1933 +       WRITE_UNLOCK(&ip_conntrack_lock);
1934 +
1935 +       return ret;
1936 +}
1937 +
1938 +/* Change tuple in an existing expectation */
1939 +int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
1940 +                              struct ip_conntrack_tuple *newtuple)
1941 +{
1942 +       int ret;
1943 +
1944 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
1945 +       WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
1946 +
1947 +       DEBUGP("change_expect:\n");
1948 +       DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
1949 +       DEBUGP("exp mask:  "); DUMP_TUPLE(&expect->mask);
1950 +       DEBUGP("newtuple:  "); DUMP_TUPLE(newtuple);
1951 +       if (expect->ct_tuple.dst.protonum == 0) {
1952 +               /* Never seen before */
1953 +               DEBUGP("change expect: never seen before\n");
1954 +               if (!ip_ct_tuple_equal(&expect->tuple, newtuple) 
1955 +                   && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
1956 +                                struct ip_conntrack_expect *, newtuple, &expect->mask)) {
1957 +                       /* Force NAT to find an unused tuple */
1958 +                       ret = -1;
1959 +               } else {
1960 +                       memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
1961 +                       memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
1962 +                       ret = 0;
1963 +               }
1964 +       } else {
1965 +               /* Resent packet */
1966 +               DEBUGP("change expect: resent packet\n");
1967 +               if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
1968 +                       ret = 0;
1969 +               } else {
1970 +                       /* Force NAT to choose again the same port */
1971 +                       ret = -1;
1972 +               }
1973 +       }
1974 +       WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
1975 +       
1976 +       return ret;
1977 +}
1978 +
1979 +/* Alter reply tuple (maybe alter helper).  If it's already taken,
1980 +   return 0 and don't do alteration. */
1981 +int ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
1982 +                            const struct ip_conntrack_tuple *newreply)
1983 +{
1984 +       WRITE_LOCK(&ip_conntrack_lock);
1985 +       if (__ip_conntrack_find(newreply, conntrack)) {
1986 +               WRITE_UNLOCK(&ip_conntrack_lock);
1987 +               return 0;
1988 +       }
1989 +       /* Should be unconfirmed, so not in hash table yet */
1990 +       IP_NF_ASSERT(!is_confirmed(conntrack));
1991 +
1992 +       DEBUGP("Altering reply tuple of %p to ", conntrack);
1993 +       DUMP_TUPLE(newreply);
1994 +
1995 +       conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
1996 +       if (!conntrack->master && list_empty(&conntrack->sibling_list))
1997 +               conntrack->helper = ip_ct_find_helper(newreply);
1998 +       WRITE_UNLOCK(&ip_conntrack_lock);
1999 +
2000 +       return 1;
2001 +}
2002 +
2003 +int ip_conntrack_helper_register(struct ip_conntrack_helper *me)
2004 +{
2005 +       MOD_INC_USE_COUNT;
2006 +
2007 +       WRITE_LOCK(&ip_conntrack_lock);
2008 +       list_prepend(&helpers, me);
2009 +       WRITE_UNLOCK(&ip_conntrack_lock);
2010 +
2011 +       return 0;
2012 +}
2013 +
2014 +static inline int unhelp(struct ip_conntrack_tuple_hash *i,
2015 +                        const struct ip_conntrack_helper *me)
2016 +{
2017 +       if (i->ctrack->helper == me) {
2018 +               /* Get rid of any expected. */
2019 +               remove_expectations(i->ctrack, 0);
2020 +               /* And *then* set helper to NULL */
2021 +               i->ctrack->helper = NULL;
2022 +       }
2023 +       return 0;
2024 +}
2025 +
2026 +void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me)
2027 +{
2028 +       unsigned int i;
2029 +
2030 +       /* Need write lock here, to delete helper. */
2031 +       WRITE_LOCK(&ip_conntrack_lock);
2032 +       LIST_DELETE(&helpers, me);
2033 +
2034 +       /* Get rid of expecteds, set helpers to NULL. */
2035 +       for (i = 0; i < ip_conntrack_htable_size; i++)
2036 +               LIST_FIND_W(&ip_conntrack_hash[i], unhelp,
2037 +                           struct ip_conntrack_tuple_hash *, me);
2038 +       WRITE_UNLOCK(&ip_conntrack_lock);
2039 +
2040 +       /* Someone could be still looking at the helper in a bh. */
2041 +       br_write_lock_bh(BR_NETPROTO_LOCK);
2042 +       br_write_unlock_bh(BR_NETPROTO_LOCK);
2043 +
2044 +       MOD_DEC_USE_COUNT;
2045 +}
2046 +
2047 +/* Refresh conntrack for this many jiffies. */
2048 +void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
2049 +{
2050 +       IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
2051 +
2052 +       WRITE_LOCK(&ip_conntrack_lock);
2053 +       /* If not in hash table, timer will not be active yet */
2054 +       if (!is_confirmed(ct))
2055 +               ct->timeout.expires = extra_jiffies;
2056 +       else {
2057 +               /* Need del_timer for race avoidance (may already be dying). */
2058 +               if (del_timer(&ct->timeout)) {
2059 +                       ct->timeout.expires = jiffies + extra_jiffies;
2060 +                       add_timer(&ct->timeout);
2061 +               }
2062 +       }
2063 +       WRITE_UNLOCK(&ip_conntrack_lock);
2064 +}
2065 +
2066 +/* Returns new sk_buff, or NULL */
2067 +struct sk_buff *
2068 +ip_ct_gather_frags(struct sk_buff *skb)
2069 +{
2070 +       struct sock *sk = skb->sk;
2071 +#ifdef CONFIG_NETFILTER_DEBUG
2072 +       unsigned int olddebug = skb->nf_debug;
2073 +#endif
2074 +       if (sk) {
2075 +               sock_hold(sk);
2076 +               skb_orphan(skb);
2077 +       }
2078 +
2079 +       local_bh_disable(); 
2080 +       skb = ip_defrag(skb);
2081 +       local_bh_enable();
2082 +
2083 +       if (!skb) {
2084 +               if (sk) sock_put(sk);
2085 +               return skb;
2086 +       } else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
2087 +               kfree_skb(skb);
2088 +               if (sk) sock_put(sk);
2089 +               return NULL;
2090 +       }
2091 +
2092 +       if (sk) {
2093 +               skb_set_owner_w(skb, sk);
2094 +               sock_put(sk);
2095 +       }
2096 +
2097 +       ip_send_check(skb->nh.iph);
2098 +       skb->nfcache |= NFC_ALTERED;
2099 +#ifdef CONFIG_NETFILTER_DEBUG
2100 +       /* Packet path as if nothing had happened. */
2101 +       skb->nf_debug = olddebug;
2102 +#endif
2103 +       return skb;
2104 +}
2105 +
2106 +/* Used by ipt_REJECT. */
2107 +static void ip_conntrack_attach(struct sk_buff *nskb, struct nf_ct_info *nfct)
2108 +{
2109 +       struct ip_conntrack *ct;
2110 +       enum ip_conntrack_info ctinfo;
2111 +
2112 +       ct = __ip_conntrack_get(nfct, &ctinfo);
2113 +
2114 +       /* This ICMP is in reverse direction to the packet which
2115 +           caused it */
2116 +       if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
2117 +               ctinfo = IP_CT_RELATED + IP_CT_IS_REPLY;
2118 +       else
2119 +               ctinfo = IP_CT_RELATED;
2120 +
2121 +       /* Attach new skbuff, and increment count */
2122 +       nskb->nfct = &ct->infos[ctinfo];
2123 +       atomic_inc(&ct->ct_general.use);
2124 +}
2125 +
2126 +static inline int
2127 +do_kill(const struct ip_conntrack_tuple_hash *i,
2128 +       int (*kill)(const struct ip_conntrack *i, void *data),
2129 +       void *data)
2130 +{
2131 +       return kill(i->ctrack, data);
2132 +}
2133 +
2134 +/* Bring out ya dead! */
2135 +static struct ip_conntrack_tuple_hash *
2136 +get_next_corpse(int (*kill)(const struct ip_conntrack *i, void *data),
2137 +               void *data, unsigned int *bucket)
2138 +{
2139 +       struct ip_conntrack_tuple_hash *h = NULL;
2140 +
2141 +       READ_LOCK(&ip_conntrack_lock);
2142 +       for (; !h && *bucket < ip_conntrack_htable_size; (*bucket)++) {
2143 +               h = LIST_FIND(&ip_conntrack_hash[*bucket], do_kill,
2144 +                             struct ip_conntrack_tuple_hash *, kill, data);
2145 +       }
2146 +       if (h)
2147 +               atomic_inc(&h->ctrack->ct_general.use);
2148 +       READ_UNLOCK(&ip_conntrack_lock);
2149 +
2150 +       return h;
2151 +}
2152 +
2153 +void
2154 +ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data),
2155 +                       void *data)
2156 +{
2157 +       struct ip_conntrack_tuple_hash *h;
2158 +       unsigned int bucket = 0;
2159 +
2160 +       while ((h = get_next_corpse(kill, data, &bucket)) != NULL) {
2161 +               /* Time to push up daises... */
2162 +               if (del_timer(&h->ctrack->timeout))
2163 +                       death_by_timeout((unsigned long)h->ctrack);
2164 +               /* ... else the timer will get him soon. */
2165 +
2166 +               ip_conntrack_put(h->ctrack);
2167 +       }
2168 +}
2169 +
2170 +/* Fast function for those who don't want to parse /proc (and I don't
2171 +   blame them). */
2172 +/* Reversing the socket's dst/src point of view gives us the reply
2173 +   mapping. */
2174 +static int
2175 +getorigdst(struct sock *sk, int optval, void *user, int *len)
2176 +{
2177 +       struct ip_conntrack_tuple_hash *h;
2178 +       struct ip_conntrack_tuple tuple;
2179 +
2180 +       IP_CT_TUPLE_U_BLANK(&tuple);
2181 +       tuple.src.ip = sk->rcv_saddr;
2182 +       tuple.src.u.tcp.port = sk->sport;
2183 +       tuple.dst.ip = sk->daddr;
2184 +       tuple.dst.u.tcp.port = sk->dport;
2185 +       tuple.dst.protonum = IPPROTO_TCP;
2186 +
2187 +       /* We only do TCP at the moment: is there a better way? */
2188 +       if (strcmp(sk->prot->name, "TCP") != 0) {
2189 +               DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
2190 +               return -ENOPROTOOPT;
2191 +       }
2192 +
2193 +       if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
2194 +               DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
2195 +                      *len, sizeof(struct sockaddr_in));
2196 +               return -EINVAL;
2197 +       }
2198 +
2199 +       h = ip_conntrack_find_get(&tuple, NULL);
2200 +       if (h) {
2201 +               struct sockaddr_in sin;
2202 +
2203 +               sin.sin_family = AF_INET;
2204 +               sin.sin_port = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
2205 +                       .tuple.dst.u.tcp.port;
2206 +               sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL]
2207 +                       .tuple.dst.ip;
2208 +
2209 +               DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
2210 +                      NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
2211 +               ip_conntrack_put(h->ctrack);
2212 +               if (copy_to_user(user, &sin, sizeof(sin)) != 0)
2213 +                       return -EFAULT;
2214 +               else
2215 +                       return 0;
2216 +       }
2217 +       DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
2218 +              NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port),
2219 +              NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port));
2220 +       return -ENOENT;
2221 +}
2222 +
2223 +static struct nf_sockopt_ops so_getorigdst
2224 += { { NULL, NULL }, PF_INET,
2225 +    0, 0, NULL, /* Setsockopts */
2226 +    SO_ORIGINAL_DST, SO_ORIGINAL_DST+1, &getorigdst,
2227 +    0, NULL };
2228 +
2229 +static int kill_all(const struct ip_conntrack *i, void *data)
2230 +{
2231 +       return 1;
2232 +}
2233 +
2234 +/* Mishearing the voices in his head, our hero wonders how he's
2235 +   supposed to kill the mall. */
2236 +void ip_conntrack_cleanup(void)
2237 +{
2238 +       ip_ct_attach = NULL;
2239 +       /* This makes sure all current packets have passed through
2240 +           netfilter framework.  Roll on, two-stage module
2241 +           delete... */
2242 +       br_write_lock_bh(BR_NETPROTO_LOCK);
2243 +       br_write_unlock_bh(BR_NETPROTO_LOCK);
2244
2245 + i_see_dead_people:
2246 +       ip_ct_selective_cleanup(kill_all, NULL);
2247 +       if (atomic_read(&ip_conntrack_count) != 0) {
2248 +               schedule();
2249 +               goto i_see_dead_people;
2250 +       }
2251 +
2252 +       kmem_cache_destroy(ip_conntrack_cachep);
2253 +       vfree(ip_conntrack_hash);
2254 +       nf_unregister_sockopt(&so_getorigdst);
2255 +}
2256 +
2257 +static int hashsize = 0;
2258 +MODULE_PARM(hashsize, "i");
2259 +
2260 +int __init ip_conntrack_init(void)
2261 +{
2262 +       unsigned int i;
2263 +       int ret;
2264 +
2265 +       /* Idea from tcp.c: use 1/16384 of memory.  On i386: 32MB
2266 +        * machine has 256 buckets.  >= 1GB machines have 8192 buckets. */
2267 +       if (hashsize) {
2268 +               ip_conntrack_htable_size = hashsize;
2269 +       } else {
2270 +               ip_conntrack_htable_size
2271 +                       = (((num_physpages << PAGE_SHIFT) / 16384)
2272 +                          / sizeof(struct list_head));
2273 +               if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
2274 +                       ip_conntrack_htable_size = 8192;
2275 +               if (ip_conntrack_htable_size < 16)
2276 +                       ip_conntrack_htable_size = 16;
2277 +       }
2278 +       ip_conntrack_max = 8 * ip_conntrack_htable_size;
2279 +
2280 +       printk("ip_conntrack version %s (%u buckets, %d max)"
2281 +              " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
2282 +              ip_conntrack_htable_size, ip_conntrack_max,
2283 +              sizeof(struct ip_conntrack));
2284 +
2285 +       ret = nf_register_sockopt(&so_getorigdst);
2286 +       if (ret != 0) {
2287 +               printk(KERN_ERR "Unable to register netfilter socket option\n");
2288 +               return ret;
2289 +       }
2290 +
2291 +       ip_conntrack_hash = vmalloc(sizeof(struct list_head)
2292 +                                   * ip_conntrack_htable_size);
2293 +       if (!ip_conntrack_hash) {
2294 +               printk(KERN_ERR "Unable to create ip_conntrack_hash\n");
2295 +               goto err_unreg_sockopt;
2296 +       }
2297 +
2298 +       ip_conntrack_cachep = kmem_cache_create("ip_conntrack",
2299 +                                               sizeof(struct ip_conntrack), 0,
2300 +                                               SLAB_HWCACHE_ALIGN, NULL, NULL);
2301 +       if (!ip_conntrack_cachep) {
2302 +               printk(KERN_ERR "Unable to create ip_conntrack slab cache\n");
2303 +               goto err_free_hash;
2304 +       }
2305 +       /* Don't NEED lock here, but good form anyway. */
2306 +       WRITE_LOCK(&ip_conntrack_lock);
2307 +       /* Sew in builtin protocols. */
2308 +       list_append(&protocol_list, &ip_conntrack_protocol_tcp);
2309 +       list_append(&protocol_list, &ip_conntrack_protocol_udp);
2310 +       list_append(&protocol_list, &ip_conntrack_protocol_icmp);
2311 +       WRITE_UNLOCK(&ip_conntrack_lock);
2312 +
2313 +       for (i = 0; i < ip_conntrack_htable_size; i++)
2314 +               INIT_LIST_HEAD(&ip_conntrack_hash[i]);
2315 +
2316 +       /* For use by ipt_REJECT */
2317 +       ip_ct_attach = ip_conntrack_attach;
2318 +       return ret;
2319 +
2320 +err_free_hash:
2321 +       vfree(ip_conntrack_hash);
2322 +err_unreg_sockopt:
2323 +       nf_unregister_sockopt(&so_getorigdst);
2324 +
2325 +       return -ENOMEM;
2326 +}
2327 diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_pptp.c linux/net/ipv4/netfilter/ip_conntrack_pptp.c
2328 --- linux_org/net/ipv4/netfilter/ip_conntrack_pptp.c    1970-01-01 01:00:00.000000000 +0100
2329 +++ linux/net/ipv4/netfilter/ip_conntrack_pptp.c        2006-10-27 14:11:52.000000000 +0200
2330 @@ -0,0 +1,637 @@
2331 +/*
2332 + * ip_conntrack_pptp.c - Version 1.9
2333 + *
2334 + * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
2335 + * PPTP is a a protocol for creating virtual private networks.
2336 + * It is a specification defined by Microsoft and some vendors
2337 + * working with Microsoft.  PPTP is built on top of a modified
2338 + * version of the Internet Generic Routing Encapsulation Protocol.
2339 + * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
2340 + * PPTP can be found in RFC 2637
2341 + *
2342 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
2343 + *
2344 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
2345 + *
2346 + * Limitations:
2347 + *      - We blindly assume that control connections are always
2348 + *        established in PNS->PAC direction.  This is a violation
2349 + *        of RFFC2673
2350 + *
2351 + * TODO: - finish support for multiple calls within one session
2352 + *        (needs expect reservations in newnat)
2353 + *      - testing of incoming PPTP calls 
2354 + *
2355 + * Changes: 
2356 + *     2002-02-05 - Version 1.3
2357 + *       - Call ip_conntrack_unexpect_related() from 
2358 + *         pptp_timeout_related() to destroy expectations in case
2359 + *         CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
2360 + *         (Philip Craig <philipc@snapgear.com>)
2361 + *       - Add Version information at module loadtime
2362 + *     2002-02-10 - Version 1.6
2363 + *       - move to C99 style initializers
2364 + *       - remove second expectation if first arrives
2365 + *
2366 + */
2367 +
2368 +#include <linux/config.h>
2369 +#include <linux/module.h>
2370 +#include <linux/netfilter.h>
2371 +#include <linux/ip.h>
2372 +#include <net/checksum.h>
2373 +#include <net/tcp.h>
2374 +
2375 +#include <linux/netfilter_ipv4/lockhelp.h>
2376 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
2377 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
2378 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
2379 +
2380 +#define IP_CT_PPTP_VERSION "1.9"
2381 +
2382 +MODULE_LICENSE("GPL");
2383 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
2384 +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
2385 +
2386 +DECLARE_LOCK(ip_pptp_lock);
2387 +
2388 +#if 0
2389 +#include "ip_conntrack_pptp_priv.h"
2390 +#define DEBUGP(format, args...)        printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
2391 +                                       ": " format, ## args)
2392 +#else
2393 +#define DEBUGP(format, args...)
2394 +#endif
2395 +
2396 +#define SECS *HZ
2397 +#define MINS * 60 SECS
2398 +#define HOURS * 60 MINS
2399 +#define DAYS * 24 HOURS
2400 +
2401 +#define PPTP_GRE_TIMEOUT               (10 MINS)
2402 +#define PPTP_GRE_STREAM_TIMEOUT        (5 DAYS)
2403 +
2404 +static int pptp_expectfn(struct ip_conntrack *ct)
2405 +{
2406 +       struct ip_conntrack *master;
2407 +       struct ip_conntrack_expect *exp;
2408 +
2409 +       DEBUGP("increasing timeouts\n");
2410 +       /* increase timeout of GRE data channel conntrack entry */
2411 +       ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
2412 +       ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
2413 +
2414 +       master = master_ct(ct);
2415 +       if (!master) {
2416 +               DEBUGP(" no master!!!\n");
2417 +               return 0;
2418 +       }
2419 +
2420 +       exp = ct->master;
2421 +       if (!exp) {
2422 +               DEBUGP("no expectation!!\n");
2423 +               return 0;
2424 +       }
2425 +
2426 +       DEBUGP("completing tuples with ct info\n");
2427 +       /* we can do this, since we're unconfirmed */
2428 +       if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == 
2429 +               htonl(master->help.ct_pptp_info.pac_call_id)) { 
2430 +               /* assume PNS->PAC */
2431 +               ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = 
2432 +                       htonl(master->help.ct_pptp_info.pns_call_id);
2433 +               ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
2434 +                       htonl(master->help.ct_pptp_info.pns_call_id);
2435 +       } else {
2436 +               /* assume PAC->PNS */
2437 +               ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
2438 +                       htonl(master->help.ct_pptp_info.pac_call_id);
2439 +               ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
2440 +                       htonl(master->help.ct_pptp_info.pac_call_id);
2441 +       }
2442 +       
2443 +       /* delete other expectation */
2444 +       if (exp->expected_list.next != &exp->expected_list) {
2445 +               struct ip_conntrack_expect *other_exp;
2446 +               struct list_head *cur_item, *next;
2447 +
2448 +               for (cur_item = master->sibling_list.next;
2449 +                    cur_item != &master->sibling_list; cur_item = next) {
2450 +                       next = cur_item->next;
2451 +                       other_exp = list_entry(cur_item,
2452 +                                              struct ip_conntrack_expect,
2453 +                                              expected_list);
2454 +                       /* remove only if occurred at same sequence number */
2455 +                       if (other_exp != exp && other_exp->seq == exp->seq) {
2456 +                               DEBUGP("unexpecting other direction\n");
2457 +                               ip_ct_gre_keymap_destroy(other_exp);
2458 +                               ip_conntrack_unexpect_related(other_exp);
2459 +                       }
2460 +               }
2461 +       }
2462 +
2463 +       return 0;
2464 +}
2465 +
2466 +/* timeout GRE data connections */
2467 +static int pptp_timeout_related(struct ip_conntrack *ct)
2468 +{
2469 +       struct list_head *cur_item, *next;
2470 +       struct ip_conntrack_expect *exp;
2471 +
2472 +       /* FIXME: do we have to lock something ? */
2473 +       for (cur_item = ct->sibling_list.next;
2474 +           cur_item != &ct->sibling_list; cur_item = next) {
2475 +               next = cur_item->next;
2476 +               exp = list_entry(cur_item, struct ip_conntrack_expect,
2477 +                                expected_list);
2478 +
2479 +               ip_ct_gre_keymap_destroy(exp);
2480 +               if (!exp->sibling) {
2481 +                       ip_conntrack_unexpect_related(exp);
2482 +                       continue;
2483 +               }
2484 +
2485 +               DEBUGP("setting timeout of conntrack %p to 0\n",
2486 +                       exp->sibling);
2487 +               exp->sibling->proto.gre.timeout = 0;
2488 +               exp->sibling->proto.gre.stream_timeout = 0;
2489 +               ip_ct_refresh(exp->sibling, 0);
2490 +       }
2491 +
2492 +       return 0;
2493 +}
2494 +
2495 +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
2496 +static inline int
2497 +exp_gre(struct ip_conntrack *master,
2498 +       u_int32_t seq,
2499 +       u_int16_t callid,
2500 +       u_int16_t peer_callid)
2501 +{
2502 +       struct ip_conntrack_expect exp;
2503 +       struct ip_conntrack_tuple inv_tuple;
2504 +
2505 +       memset(&exp, 0, sizeof(exp));
2506 +       /* tuple in original direction, PNS->PAC */
2507 +       exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
2508 +       exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
2509 +       exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
2510 +       exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
2511 +       exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
2512 +       exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
2513 +       exp.tuple.dst.protonum = IPPROTO_GRE;
2514 +
2515 +       exp.mask.src.ip = 0xffffffff;
2516 +       exp.mask.src.u.all = 0;
2517 +       exp.mask.dst.u.all = 0;
2518 +       exp.mask.dst.u.gre.key = 0xffffffff;
2519 +       exp.mask.dst.u.gre.version = 0xff;
2520 +       exp.mask.dst.u.gre.protocol = 0xffff;
2521 +       exp.mask.dst.ip = 0xffffffff;
2522 +       exp.mask.dst.protonum = 0xffff;
2523 +                       
2524 +       exp.seq = seq;
2525 +       exp.expectfn = pptp_expectfn;
2526 +
2527 +       exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
2528 +       exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
2529 +
2530 +       DEBUGP("calling expect_related ");
2531 +       DUMP_TUPLE_RAW(&exp.tuple);
2532 +       
2533 +       /* Add GRE keymap entries */
2534 +       if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
2535 +               return 1;
2536 +
2537 +       invert_tuplepr(&inv_tuple, &exp.tuple);
2538 +       if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
2539 +               ip_ct_gre_keymap_destroy(&exp);
2540 +               return 1;
2541 +       }
2542 +       
2543 +       if (ip_conntrack_expect_related(master, &exp) != 0) {
2544 +               ip_ct_gre_keymap_destroy(&exp);
2545 +               DEBUGP("cannot expect_related()\n");
2546 +               return 1;
2547 +       }
2548 +
2549 +       /* tuple in reply direction, PAC->PNS */
2550 +       exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
2551 +       exp.tuple.src.u.gre.key = htonl(ntohs(callid));
2552 +       exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
2553 +       exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
2554 +
2555 +       DEBUGP("calling expect_related ");
2556 +       DUMP_TUPLE_RAW(&exp.tuple);
2557 +       
2558 +       /* Add GRE keymap entries */
2559 +       ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
2560 +       invert_tuplepr(&inv_tuple, &exp.tuple);
2561 +       ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
2562 +       /* FIXME: cannot handle error correctly, since we need to free
2563 +        * the above keymap :( */
2564 +       
2565 +       if (ip_conntrack_expect_related(master, &exp) != 0) {
2566 +               /* free the second pair of keypmaps */
2567 +               ip_ct_gre_keymap_destroy(&exp);
2568 +               DEBUGP("cannot expect_related():\n");
2569 +               return 1;
2570 +       }
2571 +
2572 +       return 0;
2573 +}
2574 +
2575 +static inline int 
2576 +pptp_inbound_pkt(struct tcphdr *tcph,
2577 +                struct pptp_pkt_hdr *pptph, 
2578 +                size_t datalen,
2579 +                struct ip_conntrack *ct,
2580 +                enum ip_conntrack_info ctinfo)
2581 +{
2582 +       struct PptpControlHeader *ctlh;
2583 +        union pptp_ctrl_union pptpReq;
2584 +       
2585 +       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2586 +       u_int16_t msg, *cid, *pcid;
2587 +       u_int32_t seq;  
2588 +
2589 +       ctlh = (struct PptpControlHeader *) 
2590 +               ((char *) pptph + sizeof(struct pptp_pkt_hdr));
2591 +       pptpReq.rawreq = (void *) 
2592 +               ((char *) ctlh + sizeof(struct PptpControlHeader));
2593 +
2594 +       msg = ntohs(ctlh->messageType);
2595 +       DEBUGP("inbound control message %s\n", strMName[msg]);
2596 +
2597 +       switch (msg) {
2598 +       case PPTP_START_SESSION_REPLY:
2599 +               /* server confirms new control session */
2600 +               if (info->sstate < PPTP_SESSION_REQUESTED) {
2601 +                       DEBUGP("%s without START_SESS_REQUEST\n",
2602 +                               strMName[msg]);
2603 +                       break;
2604 +               }
2605 +               if (pptpReq.srep->resultCode == PPTP_START_OK)
2606 +                       info->sstate = PPTP_SESSION_CONFIRMED;
2607 +               else 
2608 +                       info->sstate = PPTP_SESSION_ERROR;
2609 +               break;
2610 +
2611 +       case PPTP_STOP_SESSION_REPLY:
2612 +               /* server confirms end of control session */
2613 +               if (info->sstate > PPTP_SESSION_STOPREQ) {
2614 +                       DEBUGP("%s without STOP_SESS_REQUEST\n",
2615 +                               strMName[msg]);
2616 +                       break;
2617 +               }
2618 +               if (pptpReq.strep->resultCode == PPTP_STOP_OK)
2619 +                       info->sstate = PPTP_SESSION_NONE;
2620 +               else
2621 +                       info->sstate = PPTP_SESSION_ERROR;
2622 +               break;
2623 +
2624 +       case PPTP_OUT_CALL_REPLY:
2625 +               /* server accepted call, we now expect GRE frames */
2626 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2627 +                       DEBUGP("%s but no session\n", strMName[msg]);
2628 +                       break;
2629 +               }
2630 +               if (info->cstate != PPTP_CALL_OUT_REQ &&
2631 +                   info->cstate != PPTP_CALL_OUT_CONF) {
2632 +                       DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
2633 +                       break;
2634 +               }
2635 +               if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
2636 +                       info->cstate = PPTP_CALL_NONE;
2637 +                       break;
2638 +               }
2639 +
2640 +               cid = &pptpReq.ocack->callID;
2641 +               pcid = &pptpReq.ocack->peersCallID;
2642 +
2643 +               info->pac_call_id = ntohs(*cid);
2644 +               
2645 +               if (htons(info->pns_call_id) != *pcid) {
2646 +                       DEBUGP("%s for unknown callid %u\n",
2647 +                               strMName[msg], ntohs(*pcid));
2648 +                       break;
2649 +               }
2650 +
2651 +               DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], 
2652 +                       ntohs(*cid), ntohs(*pcid));
2653 +               
2654 +               info->cstate = PPTP_CALL_OUT_CONF;
2655 +
2656 +               seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2657 +               if (exp_gre(ct, seq, *cid, *pcid) != 0)
2658 +                       printk("ip_conntrack_pptp: error during exp_gre\n");
2659 +               break;
2660 +
2661 +       case PPTP_IN_CALL_REQUEST:
2662 +               /* server tells us about incoming call request */
2663 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2664 +                       DEBUGP("%s but no session\n", strMName[msg]);
2665 +                       break;
2666 +               }
2667 +               pcid = &pptpReq.icack->peersCallID;
2668 +               DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2669 +               info->cstate = PPTP_CALL_IN_REQ;
2670 +               info->pac_call_id= ntohs(*pcid);
2671 +               break;
2672 +
2673 +       case PPTP_IN_CALL_CONNECT:
2674 +               /* server tells us about incoming call established */
2675 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2676 +                       DEBUGP("%s but no session\n", strMName[msg]);
2677 +                       break;
2678 +               }
2679 +               if (info->sstate != PPTP_CALL_IN_REP
2680 +                   && info->sstate != PPTP_CALL_IN_CONF) {
2681 +                       DEBUGP("%s but never sent IN_CALL_REPLY\n",
2682 +                               strMName[msg]);
2683 +                       break;
2684 +               }
2685 +
2686 +               pcid = &pptpReq.iccon->peersCallID;
2687 +               cid = &info->pac_call_id;
2688 +
2689 +               if (info->pns_call_id != ntohs(*pcid)) {
2690 +                       DEBUGP("%s for unknown CallID %u\n", 
2691 +                               strMName[msg], ntohs(*cid));
2692 +                       break;
2693 +               }
2694 +
2695 +               DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2696 +               info->cstate = PPTP_CALL_IN_CONF;
2697 +
2698 +               /* we expect a GRE connection from PAC to PNS */
2699 +               seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2700 +               if (exp_gre(ct, seq, *cid, *pcid) != 0)
2701 +                       printk("ip_conntrack_pptp: error during exp_gre\n");
2702 +
2703 +               break;
2704 +
2705 +       case PPTP_CALL_DISCONNECT_NOTIFY:
2706 +               /* server confirms disconnect */
2707 +               cid = &pptpReq.disc->callID;
2708 +               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2709 +               info->cstate = PPTP_CALL_NONE;
2710 +
2711 +               /* untrack this call id, unexpect GRE packets */
2712 +               pptp_timeout_related(ct);
2713 +               break;
2714 +
2715 +       case PPTP_WAN_ERROR_NOTIFY:
2716 +               break;
2717 +
2718 +       case PPTP_ECHO_REQUEST:
2719 +       case PPTP_ECHO_REPLY:
2720 +               /* I don't have to explain these ;) */
2721 +               break;
2722 +       default:
2723 +               DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
2724 +                       ? strMName[msg]:strMName[0], msg);
2725 +               break;
2726 +       }
2727 +
2728 +       return NF_ACCEPT;
2729 +
2730 +}
2731 +
2732 +static inline int
2733 +pptp_outbound_pkt(struct tcphdr *tcph,
2734 +                 struct pptp_pkt_hdr *pptph,
2735 +                 size_t datalen,
2736 +                 struct ip_conntrack *ct,
2737 +                 enum ip_conntrack_info ctinfo)
2738 +{
2739 +       struct PptpControlHeader *ctlh;
2740 +        union pptp_ctrl_union pptpReq;
2741 +       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2742 +       u_int16_t msg, *cid, *pcid;
2743 +
2744 +       ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
2745 +       pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
2746 +
2747 +       msg = ntohs(ctlh->messageType);
2748 +       DEBUGP("outbound control message %s\n", strMName[msg]);
2749 +
2750 +       switch (msg) {
2751 +       case PPTP_START_SESSION_REQUEST:
2752 +               /* client requests for new control session */
2753 +               if (info->sstate != PPTP_SESSION_NONE) {
2754 +                       DEBUGP("%s but we already have one",
2755 +                               strMName[msg]);
2756 +               }
2757 +               info->sstate = PPTP_SESSION_REQUESTED;
2758 +               break;
2759 +       case PPTP_STOP_SESSION_REQUEST:
2760 +               /* client requests end of control session */
2761 +               info->sstate = PPTP_SESSION_STOPREQ;
2762 +               break;
2763 +
2764 +       case PPTP_OUT_CALL_REQUEST:
2765 +               /* client initiating connection to server */
2766 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2767 +                       DEBUGP("%s but no session\n",
2768 +                               strMName[msg]);
2769 +                       break;
2770 +               }
2771 +               info->cstate = PPTP_CALL_OUT_REQ;
2772 +               /* track PNS call id */
2773 +               cid = &pptpReq.ocreq->callID;
2774 +               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2775 +               info->pns_call_id = ntohs(*cid);
2776 +               break;
2777 +       case PPTP_IN_CALL_REPLY:
2778 +               /* client answers incoming call */
2779 +               if (info->cstate != PPTP_CALL_IN_REQ
2780 +                   && info->cstate != PPTP_CALL_IN_REP) {
2781 +                       DEBUGP("%s without incall_req\n", 
2782 +                               strMName[msg]);
2783 +                       break;
2784 +               }
2785 +               if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
2786 +                       info->cstate = PPTP_CALL_NONE;
2787 +                       break;
2788 +               }
2789 +               pcid = &pptpReq.icack->peersCallID;
2790 +               if (info->pac_call_id != ntohs(*pcid)) {
2791 +                       DEBUGP("%s for unknown call %u\n", 
2792 +                               strMName[msg], ntohs(*pcid));
2793 +                       break;
2794 +               }
2795 +               DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
2796 +               /* part two of the three-way handshake */
2797 +               info->cstate = PPTP_CALL_IN_REP;
2798 +               info->pns_call_id = ntohs(pptpReq.icack->callID);
2799 +               break;
2800 +
2801 +       case PPTP_CALL_CLEAR_REQUEST:
2802 +               /* client requests hangup of call */
2803 +               if (info->sstate != PPTP_SESSION_CONFIRMED) {
2804 +                       DEBUGP("CLEAR_CALL but no session\n");
2805 +                       break;
2806 +               }
2807 +               /* FUTURE: iterate over all calls and check if
2808 +                * call ID is valid.  We don't do this without newnat,
2809 +                * because we only know about last call */
2810 +               info->cstate = PPTP_CALL_CLEAR_REQ;
2811 +               break;
2812 +       case PPTP_SET_LINK_INFO:
2813 +               break;
2814 +       case PPTP_ECHO_REQUEST:
2815 +       case PPTP_ECHO_REPLY:
2816 +               /* I don't have to explain these ;) */
2817 +               break;
2818 +       default:
2819 +               DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? 
2820 +                       strMName[msg]:strMName[0], msg);
2821 +               /* unknown: no need to create GRE masq table entry */
2822 +               break;
2823 +       }
2824 +
2825 +       return NF_ACCEPT;
2826 +}
2827 +
2828 +
2829 +/* track caller id inside control connection, call expect_related */
2830 +static int 
2831 +conntrack_pptp_help(const struct iphdr *iph, size_t len,
2832 +                   struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
2833 +
2834 +{
2835 +       struct pptp_pkt_hdr *pptph;
2836 +       
2837 +       struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
2838 +       u_int32_t tcplen = len - iph->ihl * 4;
2839 +       u_int32_t datalen = tcplen - tcph->doff * 4;
2840 +       void *datalimit;
2841 +       int dir = CTINFO2DIR(ctinfo);
2842 +       struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2843 +
2844 +       int oldsstate, oldcstate;
2845 +       int ret;
2846 +
2847 +       /* don't do any tracking before tcp handshake complete */
2848 +       if (ctinfo != IP_CT_ESTABLISHED 
2849 +           && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
2850 +               DEBUGP("ctinfo = %u, skipping\n", ctinfo);
2851 +               return NF_ACCEPT;
2852 +       }
2853 +       
2854 +       /* not a complete TCP header? */
2855 +       if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
2856 +               DEBUGP("tcplen = %u\n", tcplen);
2857 +               return NF_ACCEPT;
2858 +       }
2859 +
2860 +       /* checksum invalid? */
2861 +       if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
2862 +                       csum_partial((char *) tcph, tcplen, 0))) {
2863 +               printk(KERN_NOTICE __FILE__ ": bad csum\n");
2864 +               /* W2K PPTP server sends TCP packets with wrong checksum :(( */
2865 +               //return NF_ACCEPT;
2866 +       }
2867 +
2868 +       if (tcph->fin || tcph->rst) {
2869 +               DEBUGP("RST/FIN received, timeouting GRE\n");
2870 +               /* can't do this after real newnat */
2871 +               info->cstate = PPTP_CALL_NONE;
2872 +
2873 +               /* untrack this call id, unexpect GRE packets */
2874 +               pptp_timeout_related(ct);
2875 +       }
2876 +
2877 +
2878 +       pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
2879 +       datalimit = (void *) pptph + datalen;
2880 +
2881 +       /* not a full pptp packet header? */
2882 +       if ((void *) pptph+sizeof(*pptph) >= datalimit) {
2883 +               DEBUGP("no full PPTP header, can't track\n");
2884 +               return NF_ACCEPT;
2885 +       }
2886 +       
2887 +       /* if it's not a control message we can't do anything with it */
2888 +        if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
2889 +           ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
2890 +               DEBUGP("not a control packet\n");
2891 +               return NF_ACCEPT;
2892 +       }
2893 +
2894 +       oldsstate = info->sstate;
2895 +       oldcstate = info->cstate;
2896 +
2897 +       LOCK_BH(&ip_pptp_lock);
2898 +
2899 +       /* FIXME: We just blindly assume that the control connection is always
2900 +        * established from PNS->PAC.  However, RFC makes no guarantee */
2901 +       if (dir == IP_CT_DIR_ORIGINAL)
2902 +               /* client -> server (PNS -> PAC) */
2903 +               ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2904 +       else
2905 +               /* server -> client (PAC -> PNS) */
2906 +               ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2907 +       DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
2908 +               oldsstate, info->sstate, oldcstate, info->cstate);
2909 +       UNLOCK_BH(&ip_pptp_lock);
2910 +
2911 +       return ret;
2912 +}
2913 +
2914 +/* control protocol helper */
2915 +static struct ip_conntrack_helper pptp = { 
2916 +       .list = { NULL, NULL },
2917 +       .name = "pptp", 
2918 +       .flags = IP_CT_HELPER_F_REUSE_EXPECT,
2919 +       .me = THIS_MODULE,
2920 +       .max_expected = 2,
2921 +       .timeout = 0,
2922 +       .tuple = { .src = { .ip = 0, 
2923 +                           .u = { .tcp = { .port =  
2924 +                                   __constant_htons(PPTP_CONTROL_PORT) } } 
2925 +                         }, 
2926 +                  .dst = { .ip = 0, 
2927 +                           .u = { .all = 0 },
2928 +                           .protonum = IPPROTO_TCP
2929 +                         } 
2930 +                },
2931 +       .mask = { .src = { .ip = 0, 
2932 +                          .u = { .tcp = { .port = 0xffff } } 
2933 +                        }, 
2934 +                 .dst = { .ip = 0, 
2935 +                          .u = { .all = 0 },
2936 +                          .protonum = 0xffff 
2937 +                        } 
2938 +               },
2939 +       .help = conntrack_pptp_help
2940 +};
2941 +
2942 +/* ip_conntrack_pptp initialization */
2943 +static int __init init(void)
2944 +{
2945 +       int retcode;
2946 +
2947 +       DEBUGP(__FILE__ ": registering helper\n");
2948 +       if ((retcode = ip_conntrack_helper_register(&pptp))) {
2949 +                printk(KERN_ERR "Unable to register conntrack application "
2950 +                               "helper for pptp: %d\n", retcode);
2951 +               return -EIO;
2952 +       }
2953 +
2954 +       printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
2955 +       return 0;
2956 +}
2957 +
2958 +static void __exit fini(void)
2959 +{
2960 +       ip_conntrack_helper_unregister(&pptp);
2961 +       printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
2962 +}
2963 +
2964 +module_init(init);
2965 +module_exit(fini);
2966 +
2967 +EXPORT_SYMBOL(ip_pptp_lock);
2968 diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
2969 --- linux_org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h       1970-01-01 01:00:00.000000000 +0100
2970 +++ linux/net/ipv4/netfilter/ip_conntrack_pptp_priv.h   2006-10-27 14:11:52.000000000 +0200
2971 @@ -0,0 +1,24 @@
2972 +#ifndef _IP_CT_PPTP_PRIV_H
2973 +#define _IP_CT_PPTP_PRIV_H
2974 +
2975 +/* PptpControlMessageType names */
2976 +static const char *strMName[] = {
2977 +       "UNKNOWN_MESSAGE",
2978 +       "START_SESSION_REQUEST",
2979 +       "START_SESSION_REPLY",
2980 +       "STOP_SESSION_REQUEST",
2981 +       "STOP_SESSION_REPLY",
2982 +       "ECHO_REQUEST",
2983 +       "ECHO_REPLY",
2984 +       "OUT_CALL_REQUEST",
2985 +       "OUT_CALL_REPLY",
2986 +       "IN_CALL_REQUEST",
2987 +       "IN_CALL_REPLY",
2988 +       "IN_CALL_CONNECT",
2989 +       "CALL_CLEAR_REQUEST",
2990 +       "CALL_DISCONNECT_NOTIFY",
2991 +       "WAN_ERROR_NOTIFY",
2992 +       "SET_LINK_INFO"
2993 +};
2994 +
2995 +#endif
2996 diff -uNr linux_org/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c
2997 --- linux_org/net/ipv4/netfilter/ip_conntrack_proto_gre.c       1970-01-01 01:00:00.000000000 +0100
2998 +++ linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c   2006-10-27 14:11:52.000000000 +0200
2999 @@ -0,0 +1,343 @@
3000 +/*
3001 + * ip_conntrack_proto_gre.c - Version 1.2 
3002 + *
3003 + * Connection tracking protocol helper module for GRE.
3004 + *
3005 + * GRE is a generic encapsulation protocol, which is generally not very
3006 + * suited for NAT, as it has no protocol-specific part as port numbers.
3007 + *
3008 + * It has an optional key field, which may help us distinguishing two 
3009 + * connections between the same two hosts.
3010 + *
3011 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 
3012 + *
3013 + * PPTP is built on top of a modified version of GRE, and has a mandatory
3014 + * field called "CallID", which serves us for the same purpose as the key
3015 + * field in plain GRE.
3016 + *
3017 + * Documentation about PPTP can be found in RFC 2637
3018 + *
3019 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
3020 + *
3021 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
3022 + *
3023 + */
3024 +
3025 +#include <linux/config.h>
3026 +#include <linux/module.h>
3027 +#include <linux/types.h>
3028 +#include <linux/timer.h>
3029 +#include <linux/netfilter.h>
3030 +#include <linux/ip.h>
3031 +#include <linux/in.h>
3032 +#include <linux/list.h>
3033 +
3034 +#include <linux/netfilter_ipv4/lockhelp.h>
3035 +
3036 +DECLARE_RWLOCK(ip_ct_gre_lock);
3037 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
3038 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
3039 +
3040 +#include <linux/netfilter_ipv4/listhelp.h>
3041 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
3042 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
3043 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3044 +
3045 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
3046 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
3047 +
3048 +MODULE_LICENSE("GPL");
3049 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
3050 +MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
3051 +
3052 +/* shamelessly stolen from ip_conntrack_proto_udp.c */
3053 +#define GRE_TIMEOUT            (30*HZ)
3054 +#define GRE_STREAM_TIMEOUT     (180*HZ)
3055 +
3056 +#if 0
3057 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
3058 +                                      ": " format, ## args)
3059 +#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
3060 +                       NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
3061 +                       NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \
3062 +                       (x)->dst.u.gre.version, \
3063 +                       ntohs((x)->dst.u.gre.protocol))
3064 +#else
3065 +#define DEBUGP(x, args...)
3066 +#define DUMP_TUPLE_GRE(x)
3067 +#endif
3068 +                               
3069 +/* GRE KEYMAP HANDLING FUNCTIONS */
3070 +static LIST_HEAD(gre_keymap_list);
3071 +
3072 +static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
3073 +                               const struct ip_conntrack_tuple *t)
3074 +{
3075 +       return ((km->tuple.src.ip == t->src.ip) &&
3076 +               (km->tuple.dst.ip == t->dst.ip) &&
3077 +               (km->tuple.dst.protonum == t->dst.protonum) &&
3078 +               (km->tuple.dst.u.all == t->dst.u.all));
3079 +}
3080 +
3081 +/* look up the source key for a given tuple */
3082 +static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
3083 +{
3084 +       struct ip_ct_gre_keymap *km;
3085 +       u_int32_t key;
3086 +
3087 +       READ_LOCK(&ip_ct_gre_lock);
3088 +       km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
3089 +                       struct ip_ct_gre_keymap *, t);
3090 +       if (!km) {
3091 +               READ_UNLOCK(&ip_ct_gre_lock);
3092 +               return 0;
3093 +       }
3094 +
3095 +       key = km->tuple.src.u.gre.key;
3096 +       READ_UNLOCK(&ip_ct_gre_lock);
3097 +
3098 +       return key;
3099 +}
3100 +
3101 +/* add a single keymap entry, associate with specified expect */
3102 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
3103 +                        struct ip_conntrack_tuple *t, int reply)
3104 +{
3105 +       struct ip_ct_gre_keymap *km;
3106 +
3107 +       km = kmalloc(sizeof(*km), GFP_ATOMIC);
3108 +       if (!km)
3109 +               return -1;
3110 +
3111 +       /* initializing list head should be sufficient */
3112 +       memset(km, 0, sizeof(*km));
3113 +
3114 +       memcpy(&km->tuple, t, sizeof(*t));
3115 +
3116 +       if (!reply)
3117 +               exp->proto.gre.keymap_orig = km;
3118 +       else
3119 +               exp->proto.gre.keymap_reply = km;
3120 +
3121 +       DEBUGP("adding new entry %p: ", km);
3122 +       DUMP_TUPLE_GRE(&km->tuple);
3123 +
3124 +       WRITE_LOCK(&ip_ct_gre_lock);
3125 +       list_append(&gre_keymap_list, km);
3126 +       WRITE_UNLOCK(&ip_ct_gre_lock);
3127 +
3128 +       return 0;
3129 +}
3130 +
3131 +/* change the tuple of a keymap entry (used by nat helper) */
3132 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
3133 +                            struct ip_conntrack_tuple *t)
3134 +{
3135 +       DEBUGP("changing entry %p to: ", km);
3136 +       DUMP_TUPLE_GRE(t);
3137 +
3138 +       WRITE_LOCK(&ip_ct_gre_lock);
3139 +       memcpy(&km->tuple, t, sizeof(km->tuple));
3140 +       WRITE_UNLOCK(&ip_ct_gre_lock);
3141 +}
3142 +
3143 +/* destroy the keymap entries associated with specified expect */
3144 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
3145 +{
3146 +       DEBUGP("entering for exp %p\n", exp);
3147 +       WRITE_LOCK(&ip_ct_gre_lock);
3148 +       if (exp->proto.gre.keymap_orig) {
3149 +               DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
3150 +               list_del(&exp->proto.gre.keymap_orig->list);
3151 +               kfree(exp->proto.gre.keymap_orig);
3152 +               exp->proto.gre.keymap_orig = NULL;
3153 +       }
3154 +       if (exp->proto.gre.keymap_reply) {
3155 +               DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
3156 +               list_del(&exp->proto.gre.keymap_reply->list);
3157 +               kfree(exp->proto.gre.keymap_reply);
3158 +               exp->proto.gre.keymap_reply = NULL;
3159 +       }
3160 +       WRITE_UNLOCK(&ip_ct_gre_lock);
3161 +}
3162 +
3163 +
3164 +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
3165 +
3166 +/* invert gre part of tuple */
3167 +static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
3168 +                           const struct ip_conntrack_tuple *orig)
3169 +{
3170 +       tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol;
3171 +       tuple->dst.u.gre.version = orig->dst.u.gre.version;
3172 +
3173 +       tuple->dst.u.gre.key = orig->src.u.gre.key;
3174 +       tuple->src.u.gre.key = orig->dst.u.gre.key;
3175 +
3176 +       return 1;
3177 +}
3178 +
3179 +/* gre hdr info to tuple */
3180 +static int gre_pkt_to_tuple(const void *datah, size_t datalen,
3181 +                           struct ip_conntrack_tuple *tuple)
3182 +{
3183 +       struct gre_hdr *grehdr = (struct gre_hdr *) datah;
3184 +       struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
3185 +       u_int32_t srckey;
3186 +
3187 +       /* core guarantees 8 protocol bytes, no need for size check */
3188 +
3189 +       tuple->dst.u.gre.version = grehdr->version; 
3190 +       tuple->dst.u.gre.protocol = grehdr->protocol;
3191 +
3192 +       switch (grehdr->version) {
3193 +               case GRE_VERSION_1701:
3194 +                       if (!grehdr->key) {
3195 +                               DEBUGP("Can't track GRE without key\n");
3196 +                               return 0;
3197 +                       }
3198 +                       tuple->dst.u.gre.key = *(gre_key(grehdr));
3199 +                       break;
3200 +
3201 +               case GRE_VERSION_PPTP:
3202 +                       if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
3203 +                               DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
3204 +                               return 0;
3205 +                       }
3206 +                       tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
3207 +                       break;
3208 +
3209 +               default:
3210 +                       printk(KERN_WARNING "unknown GRE version %hu\n",
3211 +                               tuple->dst.u.gre.version);
3212 +                       return 0;
3213 +       }
3214 +
3215 +       srckey = gre_keymap_lookup(tuple);
3216 +
3217 +#if 0
3218 +       DEBUGP("found src key %x for tuple ", ntohl(srckey));
3219 +       DUMP_TUPLE_GRE(tuple);
3220 +#endif
3221 +       tuple->src.u.gre.key = srckey;
3222 +
3223 +       return 1;
3224 +}
3225 +
3226 +/* print gre part of tuple */
3227 +static unsigned int gre_print_tuple(char *buffer,
3228 +                                   const struct ip_conntrack_tuple *tuple)
3229 +{
3230 +       return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ", 
3231 +                       tuple->dst.u.gre.version,
3232 +                       ntohs(tuple->dst.u.gre.protocol),
3233 +                       ntohl(tuple->src.u.gre.key),
3234 +                       ntohl(tuple->dst.u.gre.key));
3235 +}
3236 +
3237 +/* print private data for conntrack */
3238 +static unsigned int gre_print_conntrack(char *buffer,
3239 +                                       const struct ip_conntrack *ct)
3240 +{
3241 +       return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
3242 +                      (ct->proto.gre.timeout / HZ),
3243 +                      (ct->proto.gre.stream_timeout / HZ));
3244 +}
3245 +
3246 +/* Returns verdict for packet, and may modify conntrack */
3247 +static int gre_packet(struct ip_conntrack *ct,
3248 +                     struct iphdr *iph, size_t len,
3249 +                     enum ip_conntrack_info conntrackinfo)
3250 +{
3251 +       /* If we've seen traffic both ways, this is a GRE connection.
3252 +        * Extend timeout. */
3253 +       if (ct->status & IPS_SEEN_REPLY) {
3254 +               ip_ct_refresh(ct, ct->proto.gre.stream_timeout);
3255 +               /* Also, more likely to be important, and not a probe. */
3256 +               set_bit(IPS_ASSURED_BIT, &ct->status);
3257 +       } else
3258 +               ip_ct_refresh(ct, ct->proto.gre.timeout);
3259 +       
3260 +       return NF_ACCEPT;
3261 +}
3262 +
3263 +/* Called when a new connection for this protocol found. */
3264 +static int gre_new(struct ip_conntrack *ct,
3265 +                  struct iphdr *iph, size_t len)
3266 +{ 
3267 +       DEBUGP(": ");
3268 +       DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
3269 +
3270 +       /* initialize to sane value.  Ideally a conntrack helper
3271 +        * (e.g. in case of pptp) is increasing them */
3272 +       ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
3273 +       ct->proto.gre.timeout = GRE_TIMEOUT;
3274 +
3275 +       return 1;
3276 +}
3277 +
3278 +/* Called when a conntrack entry has already been removed from the hashes
3279 + * and is about to be deleted from memory */
3280 +static void gre_destroy(struct ip_conntrack *ct)
3281 +{
3282 +       struct ip_conntrack_expect *master = ct->master;
3283 +
3284 +       DEBUGP(" entering\n");
3285 +
3286 +       if (!master) {
3287 +               DEBUGP("no master exp for ct %p\n", ct);
3288 +               return;
3289 +       }
3290 +
3291 +       ip_ct_gre_keymap_destroy(master);
3292 +}
3293 +
3294 +/* protocol helper struct */
3295 +static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
3296 +                                           "gre", 
3297 +                                           gre_pkt_to_tuple,
3298 +                                           gre_invert_tuple,
3299 +                                           gre_print_tuple,
3300 +                                           gre_print_conntrack,
3301 +                                           gre_packet,
3302 +                                           gre_new,
3303 +                                           gre_destroy,
3304 +                                           NULL,
3305 +                                           THIS_MODULE };
3306 +
3307 +/* ip_conntrack_proto_gre initialization */
3308 +static int __init init(void)
3309 +{
3310 +       int retcode;
3311 +
3312 +       if ((retcode = ip_conntrack_protocol_register(&gre))) {
3313 +                printk(KERN_ERR "Unable to register conntrack protocol "
3314 +                               "helper for gre: %d\n", retcode);
3315 +               return -EIO;
3316 +       }
3317 +
3318 +       return 0;
3319 +}
3320 +
3321 +static void __exit fini(void)
3322 +{
3323 +       struct list_head *pos, *n;
3324 +
3325 +       /* delete all keymap entries */
3326 +       WRITE_LOCK(&ip_ct_gre_lock);
3327 +       list_for_each_safe(pos, n, &gre_keymap_list) {
3328 +               DEBUGP("deleting keymap %p at module unload time\n", pos);
3329 +               list_del(pos);
3330 +               kfree(pos);
3331 +       }
3332 +       WRITE_UNLOCK(&ip_ct_gre_lock);
3333 +
3334 +       ip_conntrack_protocol_unregister(&gre); 
3335 +}
3336 +
3337 +EXPORT_SYMBOL(ip_ct_gre_keymap_add);
3338 +EXPORT_SYMBOL(ip_ct_gre_keymap_change);
3339 +EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
3340 +
3341 +module_init(init);
3342 +module_exit(fini);
3343 diff -uNr linux_org/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
3344 --- linux_org/net/ipv4/netfilter/ip_nat_core.c  2004-11-24 12:14:04.000000000 +0100
3345 +++ linux/net/ipv4/netfilter/ip_nat_core.c      2006-10-27 14:11:52.000000000 +0200
3346 @@ -430,7 +430,7 @@
3347         *tuple = *orig_tuple;
3348         while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
3349                != NULL) {
3350 -               DEBUGP("Found best for "); DUMP_TUPLE(tuple);
3351 +               DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple);
3352                 /* 3) The per-protocol part of the manip is made to
3353                    map into the range to make a unique tuple. */
3354  
3355 @@ -572,9 +572,9 @@
3356                        HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
3357                        conntrack);
3358                 DEBUGP("Original: ");
3359 -               DUMP_TUPLE(&orig_tp);
3360 +               DUMP_TUPLE_RAW(&orig_tp);
3361                 DEBUGP("New: ");
3362 -               DUMP_TUPLE(&new_tuple);
3363 +               DUMP_TUPLE_RAW(&new_tuple);
3364  #endif
3365  
3366                 /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
3367 diff -uNr linux_org/net/ipv4/netfilter/ip_nat_core.c.orig linux/net/ipv4/netfilter/ip_nat_core.c.orig
3368 --- linux_org/net/ipv4/netfilter/ip_nat_core.c.orig     1970-01-01 01:00:00.000000000 +0100
3369 +++ linux/net/ipv4/netfilter/ip_nat_core.c.orig 2004-11-24 12:14:04.000000000 +0100
3370 @@ -0,0 +1,1014 @@
3371 +/* NAT for netfilter; shared with compatibility layer. */
3372 +
3373 +/* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
3374 +   Public Licence. */
3375 +#include <linux/version.h>
3376 +#include <linux/module.h>
3377 +#include <linux/types.h>
3378 +#include <linux/timer.h>
3379 +#include <linux/skbuff.h>
3380 +#include <linux/netfilter_ipv4.h>
3381 +#include <linux/brlock.h>
3382 +#include <linux/vmalloc.h>
3383 +#include <net/checksum.h>
3384 +#include <net/icmp.h>
3385 +#include <net/ip.h>
3386 +#include <net/tcp.h>  /* For tcp_prot in getorigdst */
3387 +
3388 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
3389 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
3390 +
3391 +#include <linux/netfilter_ipv4/ip_conntrack.h>
3392 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
3393 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
3394 +#include <linux/netfilter_ipv4/ip_nat.h>
3395 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
3396 +#include <linux/netfilter_ipv4/ip_nat_core.h>
3397 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
3398 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
3399 +#include <linux/netfilter_ipv4/listhelp.h>
3400 +
3401 +#if 0
3402 +#define DEBUGP printk
3403 +#else
3404 +#define DEBUGP(format, args...)
3405 +#endif
3406 +
3407 +DECLARE_RWLOCK(ip_nat_lock);
3408 +DECLARE_RWLOCK_EXTERN(ip_conntrack_lock);
3409 +
3410 +/* Calculated at init based on memory size */
3411 +static unsigned int ip_nat_htable_size;
3412 +
3413 +static struct list_head *bysource;
3414 +static struct list_head *byipsproto;
3415 +LIST_HEAD(protos);
3416 +LIST_HEAD(helpers);
3417 +
3418 +extern struct ip_nat_protocol unknown_nat_protocol;
3419 +
3420 +/* We keep extra hashes for each conntrack, for fast searching. */
3421 +static inline size_t
3422 +hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto)
3423 +{
3424 +       /* Modified src and dst, to ensure we don't create two
3425 +           identical streams. */
3426 +       return (src + dst + proto) % ip_nat_htable_size;
3427 +}
3428 +
3429 +static inline size_t
3430 +hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto)
3431 +{
3432 +       /* Original src, to ensure we map it consistently if poss. */
3433 +       return (manip->ip + manip->u.all + proto) % ip_nat_htable_size;
3434 +}
3435 +
3436 +/* Noone using conntrack by the time this called. */
3437 +static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
3438 +{
3439 +       struct ip_nat_info *info = &conn->nat.info;
3440 +       unsigned int hs, hp;
3441 +
3442 +       if (!info->initialized)
3443 +               return;
3444 +
3445 +       IP_NF_ASSERT(info->bysource.conntrack);
3446 +       IP_NF_ASSERT(info->byipsproto.conntrack);
3447 +
3448 +       hs = hash_by_src(&conn->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src,
3449 +                        conn->tuplehash[IP_CT_DIR_ORIGINAL]
3450 +                        .tuple.dst.protonum);
3451 +
3452 +       hp = hash_by_ipsproto(conn->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip,
3453 +                             conn->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip,
3454 +                             conn->tuplehash[IP_CT_DIR_REPLY]
3455 +                             .tuple.dst.protonum);
3456 +
3457 +       WRITE_LOCK(&ip_nat_lock);
3458 +       LIST_DELETE(&bysource[hs], &info->bysource);
3459 +       LIST_DELETE(&byipsproto[hp], &info->byipsproto);
3460 +       WRITE_UNLOCK(&ip_nat_lock);
3461 +}
3462 +
3463 +/* We do checksum mangling, so if they were wrong before they're still
3464 + * wrong.  Also works for incomplete packets (eg. ICMP dest
3465 + * unreachables.) */
3466 +u_int16_t
3467 +ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
3468 +{
3469 +       u_int32_t diffs[] = { oldvalinv, newval };
3470 +       return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
3471 +                                     oldcheck^0xFFFF));
3472 +}
3473 +
3474 +static inline int cmp_proto(const struct ip_nat_protocol *i, int proto)
3475 +{
3476 +       return i->protonum == proto;
3477 +}
3478 +
3479 +struct ip_nat_protocol *
3480 +find_nat_proto(u_int16_t protonum)
3481 +{
3482 +       struct ip_nat_protocol *i;
3483 +
3484 +       MUST_BE_READ_LOCKED(&ip_nat_lock);
3485 +       i = LIST_FIND(&protos, cmp_proto, struct ip_nat_protocol *, protonum);
3486 +       if (!i)
3487 +               i = &unknown_nat_protocol;
3488 +       return i;
3489 +}
3490 +
3491 +/* Is this tuple already taken? (not by us) */
3492 +int
3493 +ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
3494 +                 const struct ip_conntrack *ignored_conntrack)
3495 +{
3496 +       /* Conntrack tracking doesn't keep track of outgoing tuples; only
3497 +          incoming ones.  NAT means they don't have a fixed mapping,
3498 +          so we invert the tuple and look for the incoming reply.
3499 +
3500 +          We could keep a separate hash if this proves too slow. */
3501 +       struct ip_conntrack_tuple reply;
3502 +
3503 +       invert_tuplepr(&reply, tuple);
3504 +       return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
3505 +}
3506 +
3507 +/* Does tuple + the source manip come within the range mr */
3508 +static int
3509 +in_range(const struct ip_conntrack_tuple *tuple,
3510 +        const struct ip_conntrack_manip *manip,
3511 +        const struct ip_nat_multi_range *mr)
3512 +{
3513 +       struct ip_nat_protocol *proto = find_nat_proto(tuple->dst.protonum);
3514 +       unsigned int i;
3515 +       struct ip_conntrack_tuple newtuple = { *manip, tuple->dst };
3516 +
3517 +       for (i = 0; i < mr->rangesize; i++) {
3518 +               /* If we are allowed to map IPs, then we must be in the
3519 +                  range specified, otherwise we must be unchanged. */
3520 +               if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
3521 +                       if (ntohl(newtuple.src.ip) < ntohl(mr->range[i].min_ip)
3522 +                           || (ntohl(newtuple.src.ip)
3523 +                               > ntohl(mr->range[i].max_ip)))
3524 +                               continue;
3525 +               } else {
3526 +                       if (newtuple.src.ip != tuple->src.ip)
3527 +                               continue;
3528 +               }
3529 +
3530 +               if ((mr->range[i].flags & IP_NAT_RANGE_PROTO_SPECIFIED)
3531 +                   && proto->in_range(&newtuple, IP_NAT_MANIP_SRC,
3532 +                                      &mr->range[i].min, &mr->range[i].max))
3533 +                       return 1;
3534 +       }
3535 +       return 0;
3536 +}
3537 +
3538 +static inline int
3539 +src_cmp(const struct ip_nat_hash *i,
3540 +       const struct ip_conntrack_tuple *tuple,
3541 +       const struct ip_nat_multi_range *mr)
3542 +{
3543 +       return (i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
3544 +               == tuple->dst.protonum
3545 +               && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
3546 +               == tuple->src.ip
3547 +               && i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
3548 +               == tuple->src.u.all
3549 +               && in_range(tuple,
3550 +                           &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
3551 +                           .tuple.src,
3552 +                           mr));
3553 +}
3554 +
3555 +/* Only called for SRC manip */
3556 +static struct ip_conntrack_manip *
3557 +find_appropriate_src(const struct ip_conntrack_tuple *tuple,
3558 +                    const struct ip_nat_multi_range *mr)
3559 +{
3560 +       unsigned int h = hash_by_src(&tuple->src, tuple->dst.protonum);
3561 +       struct ip_nat_hash *i;
3562 +
3563 +       MUST_BE_READ_LOCKED(&ip_nat_lock);
3564 +       i = LIST_FIND(&bysource[h], src_cmp, struct ip_nat_hash *, tuple, mr);
3565 +       if (i)
3566 +               return &i->conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src;
3567 +       else
3568 +               return NULL;
3569 +}
3570 +
3571 +#ifdef CONFIG_IP_NF_NAT_LOCAL
3572 +/* If it's really a local destination manip, it may need to do a
3573 +   source manip too. */
3574 +static int
3575 +do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
3576 +{
3577 +       struct rtable *rt;
3578 +
3579 +       /* FIXME: IPTOS_TOS(iph->tos) --RR */
3580 +       if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) {
3581 +               DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
3582 +                      NIPQUAD(var_ip));
3583 +               return 0;
3584 +       }
3585 +
3586 +       *other_ipp = rt->rt_src;
3587 +       ip_rt_put(rt);
3588 +       return 1;
3589 +}
3590 +#endif
3591 +
3592 +/* Simple way to iterate through all. */
3593 +static inline int fake_cmp(const struct ip_nat_hash *i,
3594 +                          u_int32_t src, u_int32_t dst, u_int16_t protonum,
3595 +                          unsigned int *score,
3596 +                          const struct ip_conntrack *conntrack)
3597 +{
3598 +       /* Compare backwards: we're dealing with OUTGOING tuples, and
3599 +           inside the conntrack is the REPLY tuple.  Don't count this
3600 +           conntrack. */
3601 +       if (i->conntrack != conntrack
3602 +           && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == dst
3603 +           && i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == src
3604 +           && (i->conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
3605 +               == protonum))
3606 +               (*score)++;
3607 +       return 0;
3608 +}
3609 +
3610 +static inline unsigned int
3611 +count_maps(u_int32_t src, u_int32_t dst, u_int16_t protonum,
3612 +          const struct ip_conntrack *conntrack)
3613 +{
3614 +       unsigned int score = 0;
3615 +       unsigned int h;
3616 +
3617 +       MUST_BE_READ_LOCKED(&ip_nat_lock);
3618 +       h = hash_by_ipsproto(src, dst, protonum);
3619 +       LIST_FIND(&byipsproto[h], fake_cmp, struct ip_nat_hash *,
3620 +                 src, dst, protonum, &score, conntrack);
3621 +
3622 +       return score;
3623 +}
3624 +
3625 +/* For [FUTURE] fragmentation handling, we want the least-used
3626 +   src-ip/dst-ip/proto triple.  Fairness doesn't come into it.  Thus
3627 +   if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
3628 +   1-65535, we don't do pro-rata allocation based on ports; we choose
3629 +   the ip with the lowest src-ip/dst-ip/proto usage.
3630 +
3631 +   If an allocation then fails (eg. all 6 ports used in the 1.2.3.4
3632 +   range), we eliminate that and try again.  This is not the most
3633 +   efficient approach, but if you're worried about that, don't hand us
3634 +   ranges you don't really have.  */
3635 +static struct ip_nat_range *
3636 +find_best_ips_proto(struct ip_conntrack_tuple *tuple,
3637 +                   const struct ip_nat_multi_range *mr,
3638 +                   const struct ip_conntrack *conntrack,
3639 +                   unsigned int hooknum)
3640 +{
3641 +       unsigned int i;
3642 +       struct {
3643 +               const struct ip_nat_range *range;
3644 +               unsigned int score;
3645 +               struct ip_conntrack_tuple tuple;
3646 +       } best = { NULL,  0xFFFFFFFF };
3647 +       u_int32_t *var_ipp, *other_ipp, saved_ip, orig_dstip;
3648 +       static unsigned int randomness = 0;
3649 +
3650 +       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
3651 +               var_ipp = &tuple->src.ip;
3652 +               saved_ip = tuple->dst.ip;
3653 +               other_ipp = &tuple->dst.ip;
3654 +       } else {
3655 +               var_ipp = &tuple->dst.ip;
3656 +               saved_ip = tuple->src.ip;
3657 +               other_ipp = &tuple->src.ip;
3658 +       }
3659 +       /* Don't do do_extra_mangle unless neccessary (overrides
3660 +           explicit socket bindings, for example) */
3661 +       orig_dstip = tuple->dst.ip;
3662 +
3663 +       IP_NF_ASSERT(mr->rangesize >= 1);
3664 +       for (i = 0; i < mr->rangesize; i++) {
3665 +               /* Host order */
3666 +               u_int32_t minip, maxip, j;
3667 +
3668 +               /* Don't do ranges which are already eliminated. */
3669 +               if (mr->range[i].flags & IP_NAT_RANGE_FULL) {
3670 +                       continue;
3671 +               }
3672 +
3673 +               if (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS) {
3674 +                       minip = ntohl(mr->range[i].min_ip);
3675 +                       maxip = ntohl(mr->range[i].max_ip);
3676 +               } else
3677 +                       minip = maxip = ntohl(*var_ipp);
3678 +
3679 +               randomness++;
3680 +               for (j = 0; j < maxip - minip + 1; j++) {
3681 +                       unsigned int score;
3682 +
3683 +                       *var_ipp = htonl(minip + (randomness + j) 
3684 +                                        % (maxip - minip + 1));
3685 +
3686 +                       /* Reset the other ip in case it was mangled by
3687 +                        * do_extra_mangle last time. */
3688 +                       *other_ipp = saved_ip;
3689 +
3690 +#ifdef CONFIG_IP_NF_NAT_LOCAL
3691 +                       if (hooknum == NF_IP_LOCAL_OUT
3692 +                           && *var_ipp != orig_dstip
3693 +                           && !do_extra_mangle(*var_ipp, other_ipp)) {
3694 +                               DEBUGP("Range %u %u.%u.%u.%u rt failed!\n",
3695 +                                      i, NIPQUAD(*var_ipp));
3696 +                               /* Can't route?  This whole range part is
3697 +                                * probably screwed, but keep trying
3698 +                                * anyway. */
3699 +                               continue;
3700 +                       }
3701 +#endif
3702 +
3703 +                       /* Count how many others map onto this. */
3704 +                       score = count_maps(tuple->src.ip, tuple->dst.ip,
3705 +                                          tuple->dst.protonum, conntrack);
3706 +                       if (score < best.score) {
3707 +                               /* Optimization: doesn't get any better than
3708 +                                  this. */
3709 +                               if (score == 0)
3710 +                                       return (struct ip_nat_range *)
3711 +                                               &mr->range[i];
3712 +
3713 +                               best.score = score;
3714 +                               best.tuple = *tuple;
3715 +                               best.range = &mr->range[i];
3716 +                       }
3717 +               }
3718 +       }
3719 +       *tuple = best.tuple;
3720 +
3721 +       /* Discard const. */
3722 +       return (struct ip_nat_range *)best.range;
3723 +}
3724 +
3725 +/* Fast version doesn't iterate through hash chains, but only handles
3726 +   common case of single IP address (null NAT, masquerade) */
3727 +static struct ip_nat_range *
3728 +find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple,
3729 +                        const struct ip_nat_multi_range *mr,
3730 +                        const struct ip_conntrack *conntrack,
3731 +                        unsigned int hooknum)
3732 +{
3733 +       if (mr->rangesize != 1
3734 +           || (mr->range[0].flags & IP_NAT_RANGE_FULL)
3735 +           || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
3736 +               && mr->range[0].min_ip != mr->range[0].max_ip))
3737 +               return find_best_ips_proto(tuple, mr, conntrack, hooknum);
3738 +
3739 +       if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
3740 +               if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
3741 +                       tuple->src.ip = mr->range[0].min_ip;
3742 +               else {
3743 +                       /* Only do extra mangle when required (breaks
3744 +                           socket binding) */
3745 +#ifdef CONFIG_IP_NF_NAT_LOCAL
3746 +                       if (tuple->dst.ip != mr->range[0].min_ip
3747 +                           && hooknum == NF_IP_LOCAL_OUT
3748 +                           && !do_extra_mangle(mr->range[0].min_ip,
3749 +                                               &tuple->src.ip))
3750 +                               return NULL;
3751 +#endif
3752 +                       tuple->dst.ip = mr->range[0].min_ip;
3753 +               }
3754 +       }
3755 +
3756 +       /* Discard const. */
3757 +       return (struct ip_nat_range *)&mr->range[0];
3758 +}
3759 +
3760 +static int
3761 +get_unique_tuple(struct ip_conntrack_tuple *tuple,
3762 +                const struct ip_conntrack_tuple *orig_tuple,
3763 +                const struct ip_nat_multi_range *mrr,
3764 +                struct ip_conntrack *conntrack,
3765 +                unsigned int hooknum)
3766 +{
3767 +       struct ip_nat_protocol *proto
3768 +               = find_nat_proto(orig_tuple->dst.protonum);
3769 +       struct ip_nat_range *rptr;
3770 +       unsigned int i;
3771 +       int ret;
3772 +
3773 +       /* We temporarily use flags for marking full parts, but we
3774 +          always clean up afterwards */
3775 +       struct ip_nat_multi_range *mr = (void *)mrr;
3776 +
3777 +       /* 1) If this srcip/proto/src-proto-part is currently mapped,
3778 +          and that same mapping gives a unique tuple within the given
3779 +          range, use that.
3780 +
3781 +          This is only required for source (ie. NAT/masq) mappings.
3782 +          So far, we don't do local source mappings, so multiple
3783 +          manips not an issue.  */
3784 +       if (hooknum == NF_IP_POST_ROUTING) {
3785 +               struct ip_conntrack_manip *manip;
3786 +
3787 +               manip = find_appropriate_src(orig_tuple, mr);
3788 +               if (manip) {
3789 +                       /* Apply same source manipulation. */
3790 +                       *tuple = ((struct ip_conntrack_tuple)
3791 +                                 { *manip, orig_tuple->dst });
3792 +                       DEBUGP("get_unique_tuple: Found current src map\n");
3793 +                       return 1;
3794 +               }
3795 +       }
3796 +
3797 +       /* 2) Select the least-used IP/proto combination in the given
3798 +          range.
3799 +       */
3800 +       *tuple = *orig_tuple;
3801 +       while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
3802 +              != NULL) {
3803 +               DEBUGP("Found best for "); DUMP_TUPLE(tuple);
3804 +               /* 3) The per-protocol part of the manip is made to
3805 +                  map into the range to make a unique tuple. */
3806 +
3807 +               /* Only bother mapping if it's not already in range
3808 +                  and unique */
3809 +               if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
3810 +                    || proto->in_range(tuple, HOOK2MANIP(hooknum),
3811 +                                       &rptr->min, &rptr->max))
3812 +                   && !ip_nat_used_tuple(tuple, conntrack)) {
3813 +                       ret = 1;
3814 +                       goto clear_fulls;
3815 +               } else {
3816 +                       if (proto->unique_tuple(tuple, rptr,
3817 +                                               HOOK2MANIP(hooknum),
3818 +                                               conntrack)) {
3819 +                               /* Must be unique. */
3820 +                               IP_NF_ASSERT(!ip_nat_used_tuple(tuple,
3821 +                                                               conntrack));
3822 +                               ret = 1;
3823 +                               goto clear_fulls;
3824 +                       } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
3825 +                               /* Try implicit source NAT; protocol
3826 +                                   may be able to play with ports to
3827 +                                   make it unique. */
3828 +                               struct ip_nat_range r
3829 +                                       = { IP_NAT_RANGE_MAP_IPS, 
3830 +                                           tuple->src.ip, tuple->src.ip,
3831 +                                           { 0 }, { 0 } };
3832 +                               DEBUGP("Trying implicit mapping\n");
3833 +                               if (proto->unique_tuple(tuple, &r,
3834 +                                                       IP_NAT_MANIP_SRC,
3835 +                                                       conntrack)) {
3836 +                                       /* Must be unique. */
3837 +                                       IP_NF_ASSERT(!ip_nat_used_tuple
3838 +                                                    (tuple, conntrack));
3839 +                                       ret = 1;
3840 +                                       goto clear_fulls;
3841 +                               }
3842 +                       }
3843 +                       DEBUGP("Protocol can't get unique tuple %u.\n",
3844 +                              hooknum);
3845 +               }
3846 +
3847 +               /* Eliminate that from range, and try again. */
3848 +               rptr->flags |= IP_NAT_RANGE_FULL;
3849 +               *tuple = *orig_tuple;
3850 +       }
3851 +
3852 +       ret = 0;
3853 +
3854 + clear_fulls:
3855 +       /* Clear full flags. */
3856 +       IP_NF_ASSERT(mr->rangesize >= 1);
3857 +       for (i = 0; i < mr->rangesize; i++)
3858 +               mr->range[i].flags &= ~IP_NAT_RANGE_FULL;
3859 +
3860 +       return ret;
3861 +}
3862 +
3863 +static inline int
3864 +helper_cmp(const struct ip_nat_helper *helper,
3865 +          const struct ip_conntrack_tuple *tuple)
3866 +{
3867 +       return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
3868 +}
3869 +
3870 +/* Where to manip the reply packets (will be reverse manip). */
3871 +static unsigned int opposite_hook[NF_IP_NUMHOOKS]
3872 += { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
3873 +    [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
3874 +#ifdef CONFIG_IP_NF_NAT_LOCAL
3875 +    [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN,
3876 +    [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,
3877 +#endif
3878 +};
3879 +
3880 +unsigned int
3881 +ip_nat_setup_info(struct ip_conntrack *conntrack,
3882 +                 const struct ip_nat_multi_range *mr,
3883 +                 unsigned int hooknum)
3884 +{
3885 +       struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
3886 +       struct ip_conntrack_tuple orig_tp;
3887 +       struct ip_nat_info *info = &conntrack->nat.info;
3888 +       int in_hashes = info->initialized;
3889 +
3890 +       MUST_BE_WRITE_LOCKED(&ip_nat_lock);
3891 +       IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
3892 +                    || hooknum == NF_IP_POST_ROUTING
3893 +                    || hooknum == NF_IP_LOCAL_IN
3894 +                    || hooknum == NF_IP_LOCAL_OUT);
3895 +       IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
3896 +       IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
3897 +
3898 +       /* What we've got will look like inverse of reply. Normally
3899 +          this is what is in the conntrack, except for prior
3900 +          manipulations (future optimization: if num_manips == 0,
3901 +          orig_tp =
3902 +          conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
3903 +       invert_tuplepr(&orig_tp,
3904 +                      &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
3905 +
3906 +#if 0
3907 +       {
3908 +       unsigned int i;
3909 +
3910 +       DEBUGP("Hook %u (%s), ", hooknum,
3911 +              HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST");
3912 +       DUMP_TUPLE(&orig_tp);
3913 +       DEBUGP("Range %p: ", mr);
3914 +       for (i = 0; i < mr->rangesize; i++) {
3915 +               DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n",
3916 +                      i,
3917 +                      (mr->range[i].flags & IP_NAT_RANGE_MAP_IPS)
3918 +                      ? " MAP_IPS" : "",
3919 +                      (mr->range[i].flags
3920 +                       & IP_NAT_RANGE_PROTO_SPECIFIED)
3921 +                      ? " PROTO_SPECIFIED" : "",
3922 +                      (mr->range[i].flags & IP_NAT_RANGE_FULL)
3923 +                      ? " FULL" : "",
3924 +                      NIPQUAD(mr->range[i].min_ip),
3925 +                      NIPQUAD(mr->range[i].max_ip),
3926 +                      mr->range[i].min.all,
3927 +                      mr->range[i].max.all);
3928 +       }
3929 +       }
3930 +#endif
3931 +
3932 +       do {
3933 +               if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack,
3934 +                                     hooknum)) {
3935 +                       DEBUGP("ip_nat_setup_info: Can't get unique for %p.\n",
3936 +                              conntrack);
3937 +                       return NF_DROP;
3938 +               }
3939 +
3940 +#if 0
3941 +               DEBUGP("Hook %u (%s) %p\n", hooknum,
3942 +                      HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
3943 +                      conntrack);
3944 +               DEBUGP("Original: ");
3945 +               DUMP_TUPLE(&orig_tp);
3946 +               DEBUGP("New: ");
3947 +               DUMP_TUPLE(&new_tuple);
3948 +#endif
3949 +
3950 +               /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
3951 +                  the original (A/B/C/D') and the mangled one (E/F/G/H').
3952 +
3953 +                  We're only allowed to work with the SRC per-proto
3954 +                  part, so we create inverses of both to start, then
3955 +                  derive the other fields we need.  */
3956 +
3957 +               /* Reply connection: simply invert the new tuple
3958 +                   (G/H/E/F') */
3959 +               invert_tuplepr(&reply, &new_tuple);
3960 +
3961 +               /* Alter conntrack table so it recognizes replies.
3962 +                   If fail this race (reply tuple now used), repeat. */
3963 +       } while (!ip_conntrack_alter_reply(conntrack, &reply));
3964 +
3965 +       /* FIXME: We can simply used existing conntrack reply tuple
3966 +           here --RR */
3967 +       /* Create inverse of original: C/D/A/B' */
3968 +       invert_tuplepr(&inv_tuple, &orig_tp);
3969 +
3970 +       /* Has source changed?. */
3971 +       if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) {
3972 +               /* In this direction, a source manip. */
3973 +               info->manips[info->num_manips++] =
3974 +                       ((struct ip_nat_info_manip)
3975 +                        { IP_CT_DIR_ORIGINAL, hooknum,
3976 +                          IP_NAT_MANIP_SRC, new_tuple.src });
3977 +
3978 +               IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
3979 +
3980 +               /* In the reverse direction, a destination manip. */
3981 +               info->manips[info->num_manips++] =
3982 +                       ((struct ip_nat_info_manip)
3983 +                        { IP_CT_DIR_REPLY, opposite_hook[hooknum],
3984 +                          IP_NAT_MANIP_DST, orig_tp.src });
3985 +               IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
3986 +       }
3987 +
3988 +       /* Has destination changed? */
3989 +       if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) {
3990 +               /* In this direction, a destination manip */
3991 +               info->manips[info->num_manips++] =
3992 +                       ((struct ip_nat_info_manip)
3993 +                        { IP_CT_DIR_ORIGINAL, hooknum,
3994 +                          IP_NAT_MANIP_DST, reply.src });
3995 +
3996 +               IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
3997 +
3998 +               /* In the reverse direction, a source manip. */
3999 +               info->manips[info->num_manips++] =
4000 +                       ((struct ip_nat_info_manip)
4001 +                        { IP_CT_DIR_REPLY, opposite_hook[hooknum],
4002 +                          IP_NAT_MANIP_SRC, inv_tuple.src });
4003 +               IP_NF_ASSERT(info->num_manips <= IP_NAT_MAX_MANIPS);
4004 +       }
4005 +
4006 +       /* If there's a helper, assign it; based on new tuple. */
4007 +       if (!conntrack->master)
4008 +               info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *,
4009 +                                        &reply);
4010 +
4011 +       /* It's done. */
4012 +       info->initialized |= (1 << HOOK2MANIP(hooknum));
4013 +
4014 +       if (in_hashes) {
4015 +               IP_NF_ASSERT(info->bysource.conntrack);
4016 +               replace_in_hashes(conntrack, info);
4017 +       } else {
4018 +               place_in_hashes(conntrack, info);
4019 +       }
4020 +
4021 +       return NF_ACCEPT;
4022 +}
4023 +
4024 +void replace_in_hashes(struct ip_conntrack *conntrack,
4025 +                      struct ip_nat_info *info)
4026 +{
4027 +       /* Source has changed, so replace in hashes. */
4028 +       unsigned int srchash
4029 +               = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4030 +                             .tuple.src,
4031 +                             conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4032 +                             .tuple.dst.protonum);
4033 +       /* We place packet as seen OUTGOUNG in byips_proto hash
4034 +           (ie. reverse dst and src of reply packet. */
4035 +       unsigned int ipsprotohash
4036 +               = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
4037 +                                  .tuple.dst.ip,
4038 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
4039 +                                  .tuple.src.ip,
4040 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
4041 +                                  .tuple.dst.protonum);
4042 +
4043 +       IP_NF_ASSERT(info->bysource.conntrack == conntrack);
4044 +       MUST_BE_WRITE_LOCKED(&ip_nat_lock);
4045 +
4046 +       list_del(&info->bysource.list);
4047 +       list_del(&info->byipsproto.list);
4048 +
4049 +       list_prepend(&bysource[srchash], &info->bysource);
4050 +       list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
4051 +}
4052 +
4053 +void place_in_hashes(struct ip_conntrack *conntrack,
4054 +                    struct ip_nat_info *info)
4055 +{
4056 +       unsigned int srchash
4057 +               = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4058 +                             .tuple.src,
4059 +                             conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
4060 +                             .tuple.dst.protonum);
4061 +       /* We place packet as seen OUTGOUNG in byips_proto hash
4062 +           (ie. reverse dst and src of reply packet. */
4063 +       unsigned int ipsprotohash
4064 +               = hash_by_ipsproto(conntrack->tuplehash[IP_CT_DIR_REPLY]
4065 +                                  .tuple.dst.ip,
4066 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
4067 +                                  .tuple.src.ip,
4068 +                                  conntrack->tuplehash[IP_CT_DIR_REPLY]
4069 +                                  .tuple.dst.protonum);
4070 +
4071 +       IP_NF_ASSERT(!info->bysource.conntrack);
4072 +
4073 +       MUST_BE_WRITE_LOCKED(&ip_nat_lock);
4074 +       info->byipsproto.conntrack = conntrack;
4075 +       info->bysource.conntrack = conntrack;
4076 +
4077 +       list_prepend(&bysource[srchash], &info->bysource);
4078 +       list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
4079 +}
4080 +
4081 +static void
4082 +manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
4083 +         const struct ip_conntrack_manip *manip,
4084 +         enum ip_nat_manip_type maniptype,
4085 +         __u32 *nfcache)
4086 +{
4087 +       *nfcache |= NFC_ALTERED;
4088 +       find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype);
4089 +
4090 +       if (maniptype == IP_NAT_MANIP_SRC) {
4091 +               iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
4092 +                                               iph->check);
4093 +               iph->saddr = manip->ip;
4094 +       } else {
4095 +               iph->check = ip_nat_cheat_check(~iph->daddr, manip->ip,
4096 +                                               iph->check);
4097 +               iph->daddr = manip->ip;
4098 +       }
4099 +#if 0
4100 +       if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
4101 +               DEBUGP("IP: checksum on packet bad.\n");
4102 +
4103 +       if (proto == IPPROTO_TCP) {
4104 +               void *th = (u_int32_t *)iph + iph->ihl;
4105 +               if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr,
4106 +                                csum_partial((char *)th, len-4*iph->ihl, 0)))
4107 +                       DEBUGP("TCP: checksum on packet bad\n");
4108 +       }
4109 +#endif
4110 +}
4111 +
4112 +static inline int exp_for_packet(struct ip_conntrack_expect *exp,
4113 +                                struct sk_buff **pskb)
4114 +{
4115 +       struct ip_conntrack_protocol *proto;
4116 +       int ret = 1;
4117 +
4118 +       MUST_BE_READ_LOCKED(&ip_conntrack_lock);
4119 +       proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol);
4120 +       if (proto->exp_matches_pkt)
4121 +               ret = proto->exp_matches_pkt(exp, pskb);
4122 +
4123 +       return ret;
4124 +}
4125 +
4126 +/* Do packet manipulations according to binding. */
4127 +unsigned int
4128 +do_bindings(struct ip_conntrack *ct,
4129 +           enum ip_conntrack_info ctinfo,
4130 +           struct ip_nat_info *info,
4131 +           unsigned int hooknum,
4132 +           struct sk_buff **pskb)
4133 +{
4134 +       unsigned int i;
4135 +       struct ip_nat_helper *helper;
4136 +       enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
4137 +       int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
4138 +
4139 +       /* Need nat lock to protect against modification, but neither
4140 +          conntrack (referenced) and helper (deleted with
4141 +          synchronize_bh()) can vanish. */
4142 +       READ_LOCK(&ip_nat_lock);
4143 +       for (i = 0; i < info->num_manips; i++) {
4144 +               /* raw socket (tcpdump) may have clone of incoming
4145 +                   skb: don't disturb it --RR */
4146 +               if (skb_cloned(*pskb) && !(*pskb)->sk) {
4147 +                       struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
4148 +                       if (!nskb) {
4149 +                               READ_UNLOCK(&ip_nat_lock);
4150 +                               return NF_DROP;
4151 +                       }
4152 +                       kfree_skb(*pskb);
4153 +                       *pskb = nskb;
4154 +               }
4155 +
4156 +               if (info->manips[i].direction == dir
4157 +                   && info->manips[i].hooknum == hooknum) {
4158 +                       DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
4159 +                              *pskb,
4160 +                              info->manips[i].maniptype == IP_NAT_MANIP_SRC
4161 +                              ? "SRC" : "DST",
4162 +                              NIPQUAD(info->manips[i].manip.ip),
4163 +                              htons(info->manips[i].manip.u.all));
4164 +                       manip_pkt((*pskb)->nh.iph->protocol,
4165 +                                 (*pskb)->nh.iph,
4166 +                                 (*pskb)->len,
4167 +                                 &info->manips[i].manip,
4168 +                                 info->manips[i].maniptype,
4169 +                                 &(*pskb)->nfcache);
4170 +               }
4171 +       }
4172 +       helper = info->helper;
4173 +       READ_UNLOCK(&ip_nat_lock);
4174 +
4175 +       if (helper) {
4176 +               struct ip_conntrack_expect *exp = NULL;
4177 +               struct list_head *cur_item;
4178 +               int ret = NF_ACCEPT;
4179 +               int helper_called = 0;
4180 +
4181 +               DEBUGP("do_bindings: helper existing for (%p)\n", ct);
4182 +
4183 +               /* Always defragged for helpers */
4184 +               IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
4185 +                              & htons(IP_MF|IP_OFFSET)));
4186 +
4187 +               /* Have to grab read lock before sibling_list traversal */
4188 +               READ_LOCK(&ip_conntrack_lock);
4189 +               list_for_each_prev(cur_item, &ct->sibling_list) { 
4190 +                       exp = list_entry(cur_item, struct ip_conntrack_expect, 
4191 +                                        expected_list);
4192 +                                        
4193 +                       /* if this expectation is already established, skip */
4194 +                       if (exp->sibling)
4195 +                               continue;
4196 +
4197 +                       if (exp_for_packet(exp, pskb)) {
4198 +                               /* FIXME: May be true multiple times in the
4199 +                                * case of UDP!! */
4200 +                               DEBUGP("calling nat helper (exp=%p) for packet\n", exp);
4201 +                               ret = helper->help(ct, exp, info, ctinfo, 
4202 +                                                  hooknum, pskb);
4203 +                               if (ret != NF_ACCEPT) {
4204 +                                       READ_UNLOCK(&ip_conntrack_lock);
4205 +                                       return ret;
4206 +                               }
4207 +                               helper_called = 1;
4208 +                       }
4209 +               }
4210 +               /* Helper might want to manip the packet even when there is no
4211 +                * matching expectation for this packet */
4212 +               if (!helper_called && helper->flags & IP_NAT_HELPER_F_ALWAYS) {
4213 +                       DEBUGP("calling nat helper for packet without expectation\n");
4214 +                       ret = helper->help(ct, NULL, info, ctinfo, 
4215 +                                          hooknum, pskb);
4216 +                       if (ret != NF_ACCEPT) {
4217 +                               READ_UNLOCK(&ip_conntrack_lock);
4218 +                               return ret;
4219 +                       }
4220 +               }
4221 +               READ_UNLOCK(&ip_conntrack_lock);
4222 +               
4223 +               /* Adjust sequence number only once per packet 
4224 +                * (helper is called at all hooks) */
4225 +               if (is_tcp && (hooknum == NF_IP_POST_ROUTING
4226 +                              || hooknum == NF_IP_LOCAL_IN)) {
4227 +                       DEBUGP("ip_nat_core: adjusting sequence number\n");
4228 +                       /* future: put this in a l4-proto specific function,
4229 +                        * and call this function here. */
4230 +                       ip_nat_seq_adjust(*pskb, ct, ctinfo);
4231 +               }
4232 +
4233 +               return ret;
4234 +
4235 +       } else 
4236 +               return NF_ACCEPT;
4237 +
4238 +       /* not reached */
4239 +}
4240 +
4241 +unsigned int
4242 +icmp_reply_translation(struct sk_buff *skb,
4243 +                      struct ip_conntrack *conntrack,
4244 +                      unsigned int hooknum,
4245 +                      int dir)
4246 +{
4247 +       struct iphdr *iph = skb->nh.iph;
4248 +       struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
4249 +       struct iphdr *inner = (struct iphdr *)(hdr + 1);
4250 +       size_t datalen = skb->len - ((void *)inner - (void *)iph);
4251 +       unsigned int i;
4252 +       struct ip_nat_info *info = &conntrack->nat.info;
4253 +
4254 +       IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
4255 +       /* Must be RELATED */
4256 +       IP_NF_ASSERT(skb->nfct
4257 +                    - ((struct ip_conntrack *)skb->nfct->master)->infos
4258 +                    == IP_CT_RELATED
4259 +                    || skb->nfct
4260 +                    - ((struct ip_conntrack *)skb->nfct->master)->infos
4261 +                    == IP_CT_RELATED+IP_CT_IS_REPLY);
4262 +
4263 +       /* Redirects on non-null nats must be dropped, else they'll
4264 +           start talking to each other without our translation, and be
4265 +           confused... --RR */
4266 +       if (hdr->type == ICMP_REDIRECT) {
4267 +               /* Don't care about races here. */
4268 +               if (info->initialized
4269 +                   != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
4270 +                   || info->num_manips != 0)
4271 +                       return NF_DROP;
4272 +       }
4273 +
4274 +       DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
4275 +              skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
4276 +       /* Note: May not be from a NAT'd host, but probably safest to
4277 +          do translation always as if it came from the host itself
4278 +          (even though a "host unreachable" coming from the host
4279 +          itself is a bit weird).
4280 +
4281 +          More explanation: some people use NAT for anonymizing.
4282 +          Also, CERT recommends dropping all packets from private IP
4283 +          addresses (although ICMP errors from internal links with
4284 +          such addresses are not too uncommon, as Alan Cox points
4285 +          out) */
4286 +
4287 +       READ_LOCK(&ip_nat_lock);
4288 +       for (i = 0; i < info->num_manips; i++) {
4289 +               DEBUGP("icmp_reply: manip %u dir %s hook %u\n",
4290 +                      i, info->manips[i].direction == IP_CT_DIR_ORIGINAL ?
4291 +                      "ORIG" : "REPLY", info->manips[i].hooknum);
4292 +
4293 +               if (info->manips[i].direction != dir)
4294 +                       continue;
4295 +
4296 +               /* Mapping the inner packet is just like a normal
4297 +                  packet, except it was never src/dst reversed, so
4298 +                  where we would normally apply a dst manip, we apply
4299 +                  a src, and vice versa. */
4300 +               if (info->manips[i].hooknum == hooknum) {
4301 +                       DEBUGP("icmp_reply: inner %s -> %u.%u.%u.%u %u\n",
4302 +                              info->manips[i].maniptype == IP_NAT_MANIP_SRC
4303 +                              ? "DST" : "SRC",
4304 +                              NIPQUAD(info->manips[i].manip.ip),
4305 +                              ntohs(info->manips[i].manip.u.udp.port));
4306 +                       manip_pkt(inner->protocol, inner,
4307 +                                 skb->len - ((void *)inner - (void *)iph),
4308 +                                 &info->manips[i].manip,
4309 +                                 !info->manips[i].maniptype,
4310 +                                 &skb->nfcache);
4311 +                       /* Outer packet needs to have IP header NATed like
4312 +                          it's a reply. */
4313 +
4314 +                       /* Use mapping to map outer packet: 0 give no
4315 +                           per-proto mapping */
4316 +                       DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
4317 +                              info->manips[i].maniptype == IP_NAT_MANIP_SRC
4318 +                              ? "SRC" : "DST",
4319 +                              NIPQUAD(info->manips[i].manip.ip));
4320 +                       manip_pkt(0, iph, skb->len,
4321 +                                 &info->manips[i].manip,
4322 +                                 info->manips[i].maniptype,
4323 +                                 &skb->nfcache);
4324 +               }
4325 +       }
4326 +       READ_UNLOCK(&ip_nat_lock);
4327 +
4328 +       /* Since we mangled inside ICMP packet, recalculate its
4329 +          checksum from scratch.  (Hence the handling of incorrect
4330 +          checksums in conntrack, so we don't accidentally fix one.)  */
4331 +       hdr->checksum = 0;
4332 +       hdr->checksum = ip_compute_csum((unsigned char *)hdr,
4333 +                                       sizeof(*hdr) + datalen);
4334 +
4335 +       return NF_ACCEPT;
4336 +}
4337 +
4338 +int __init ip_nat_init(void)
4339 +{
4340 +       size_t i;
4341 +
4342 +       /* Leave them the same for the moment. */
4343 +       ip_nat_htable_size = ip_conntrack_htable_size;
4344 +
4345 +       /* One vmalloc for both hash tables */
4346 +       bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size*2);
4347 +       if (!bysource) {
4348 +               return -ENOMEM;
4349 +       }
4350 +       byipsproto = bysource + ip_nat_htable_size;
4351 +
4352 +       /* Sew in builtin protocols. */
4353 +       WRITE_LOCK(&ip_nat_lock);
4354 +       list_append(&protos, &ip_nat_protocol_tcp);
4355 +       list_append(&protos, &ip_nat_protocol_udp);
4356 +       list_append(&protos, &ip_nat_protocol_icmp);
4357 +       WRITE_UNLOCK(&ip_nat_lock);
4358 +
4359 +       for (i = 0; i < ip_nat_htable_size; i++) {
4360 +               INIT_LIST_HEAD(&bysource[i]);
4361 +               INIT_LIST_HEAD(&byipsproto[i]);
4362 +       }
4363 +
4364 +       /* FIXME: Man, this is a hack.  <SIGH> */
4365 +       IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
4366 +       ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
4367 +
4368 +       return 0;
4369 +}
4370 +
4371 +/* Clear NAT section of all conntracks, in case we're loaded again. */
4372 +static int clean_nat(const struct ip_conntrack *i, void *data)
4373 +{
4374 +       memset((void *)&i->nat, 0, sizeof(i->nat));
4375 +       return 0;
4376 +}
4377 +
4378 +/* Not __exit: called from ip_nat_standalone.c:init_or_cleanup() --RR */
4379 +void ip_nat_cleanup(void)
4380 +{
4381 +       ip_ct_selective_cleanup(&clean_nat, NULL);
4382 +       ip_conntrack_destroyed = NULL;
4383 +       vfree(bysource);
4384 +}
4385 diff -uNr linux_org/net/ipv4/netfilter/ip_nat_pptp.c linux/net/ipv4/netfilter/ip_nat_pptp.c
4386 --- linux_org/net/ipv4/netfilter/ip_nat_pptp.c  1970-01-01 01:00:00.000000000 +0100
4387 +++ linux/net/ipv4/netfilter/ip_nat_pptp.c      2006-10-27 14:11:52.000000000 +0200
4388 @@ -0,0 +1,475 @@
4389 +/*
4390 + * ip_nat_pptp.c       - Version 1.5
4391 + *
4392 + * NAT support for PPTP (Point to Point Tunneling Protocol).
4393 + * PPTP is a a protocol for creating virtual private networks.
4394 + * It is a specification defined by Microsoft and some vendors
4395 + * working with Microsoft.  PPTP is built on top of a modified
4396 + * version of the Internet Generic Routing Encapsulation Protocol.
4397 + * GRE is defined in RFC 1701 and RFC 1702.  Documentation of
4398 + * PPTP can be found in RFC 2637
4399 + *
4400 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
4401 + *
4402 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
4403 + *
4404 + * TODO: - Support for multiple calls within one session
4405 + *        (needs netfilter newnat code)
4406 + *      - NAT to a unique tuple, not to TCP source port
4407 + *        (needs netfilter tuple reservation)
4408 + *
4409 + * Changes:
4410 + *     2002-02-10 - Version 1.3
4411 + *       - Use ip_nat_mangle_tcp_packet() because of cloned skb's
4412 + *        in local connections (Philip Craig <philipc@snapgear.com>)
4413 + *       - add checks for magicCookie and pptp version
4414 + *       - make argument list of pptp_{out,in}bound_packet() shorter
4415 + *       - move to C99 style initializers
4416 + *       - print version number at module loadtime
4417 + *     2003-09-22 - Version 1.5
4418 + *       - use SNATed tcp sourceport as callid, since we get called before
4419 + *         TCP header is mangled (Philip Craig <philipc@snapgear.com>)
4420 + * 
4421 + */
4422 +
4423 +#include <linux/config.h>
4424 +#include <linux/module.h>
4425 +#include <linux/ip.h>
4426 +#include <linux/tcp.h>
4427 +#include <net/tcp.h>
4428 +#include <linux/netfilter_ipv4/ip_nat.h>
4429 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
4430 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
4431 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
4432 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
4433 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
4434 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
4435 +
4436 +#define IP_NAT_PPTP_VERSION "1.5"
4437 +
4438 +MODULE_LICENSE("GPL");
4439 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
4440 +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
4441 +
4442 +
4443 +#if 0
4444 +#include "ip_conntrack_pptp_priv.h"
4445 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
4446 +                                      ": " format, ## args)
4447 +#else
4448 +#define DEBUGP(format, args...)
4449 +#endif
4450 +
4451 +static unsigned int
4452 +pptp_nat_expected(struct sk_buff **pskb,
4453 +                 unsigned int hooknum,
4454 +                 struct ip_conntrack *ct,
4455 +                 struct ip_nat_info *info)
4456 +{
4457 +       struct ip_conntrack *master = master_ct(ct);
4458 +       struct ip_nat_multi_range mr;
4459 +       struct ip_ct_pptp_master *ct_pptp_info;
4460 +       struct ip_nat_pptp *nat_pptp_info;
4461 +       u_int32_t newip, newcid;
4462 +       int ret;
4463 +
4464 +       IP_NF_ASSERT(info);
4465 +       IP_NF_ASSERT(master);
4466 +       IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
4467 +
4468 +       DEBUGP("we have a connection!\n");
4469 +
4470 +       LOCK_BH(&ip_pptp_lock);
4471 +       ct_pptp_info = &master->help.ct_pptp_info;
4472 +       nat_pptp_info = &master->nat.help.nat_pptp_info;
4473 +
4474 +       /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
4475 +        * (unmanipulated) values */
4476 +       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
4477 +               DEBUGP("completing tuples with NAT info \n");
4478 +               /* we can do this, since we're unconfirmed */
4479 +               if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
4480 +                       htonl(ct_pptp_info->pac_call_id)) {     
4481 +                       /* assume PNS->PAC */
4482 +                       ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
4483 +                               htonl(nat_pptp_info->pns_call_id);
4484 +                       ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
4485 +                               htonl(nat_pptp_info->pns_call_id);
4486 +                       newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
4487 +                       newcid = htonl(nat_pptp_info->pac_call_id);
4488 +               } else {
4489 +                       /* assume PAC->PNS */
4490 +                       ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
4491 +                               htonl(nat_pptp_info->pac_call_id);
4492 +                       ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
4493 +                               htonl(nat_pptp_info->pac_call_id);
4494 +                       newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
4495 +                       newcid = htonl(nat_pptp_info->pns_call_id);
4496 +               }
4497 +       } else {
4498 +               if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
4499 +                       htonl(ct_pptp_info->pac_call_id)) {     
4500 +                       /* assume PNS->PAC */
4501 +                       newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
4502 +                       newcid = htonl(ct_pptp_info->pns_call_id);
4503 +               }
4504 +               else {
4505 +                       /* assume PAC->PNS */
4506 +                       newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
4507 +                       newcid = htonl(ct_pptp_info->pac_call_id);
4508 +               }
4509 +       }
4510 +
4511 +       mr.rangesize = 1;
4512 +       mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
4513 +       mr.range[0].min_ip = mr.range[0].max_ip = newip;
4514 +       mr.range[0].min = mr.range[0].max = 
4515 +               ((union ip_conntrack_manip_proto ) { newcid }); 
4516 +       DEBUGP("change ip to %u.%u.%u.%u\n", 
4517 +               NIPQUAD(newip));
4518 +       DEBUGP("change key to 0x%x\n", ntohl(newcid));
4519 +       ret = ip_nat_setup_info(ct, &mr, hooknum);
4520 +
4521 +       UNLOCK_BH(&ip_pptp_lock);
4522 +
4523 +       return ret;
4524 +
4525 +}
4526 +
4527 +/* outbound packets == from PNS to PAC */
4528 +static inline unsigned int
4529 +pptp_outbound_pkt(struct sk_buff **pskb,
4530 +                 struct ip_conntrack *ct,
4531 +                 enum ip_conntrack_info ctinfo,
4532 +                 struct ip_conntrack_expect *exp)
4533 +
4534 +{
4535 +       struct iphdr *iph = (*pskb)->nh.iph;
4536 +       struct tcphdr *tcph = (void *) iph + iph->ihl*4;
4537 +       struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) 
4538 +                                       ((void *)tcph + tcph->doff*4);
4539 +
4540 +       struct PptpControlHeader *ctlh;
4541 +       union pptp_ctrl_union pptpReq;
4542 +       struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
4543 +       struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
4544 +
4545 +       u_int16_t msg, *cid = NULL, new_callid;
4546 +
4547 +       /* FIXME: size checks !!! */
4548 +       ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
4549 +       pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
4550 +
4551 +       new_callid = htons(ct_pptp_info->pns_call_id);
4552 +       
4553 +       switch (msg = ntohs(ctlh->messageType)) {
4554 +               case PPTP_OUT_CALL_REQUEST:
4555 +                       cid = &pptpReq.ocreq->callID;
4556 +                       /* FIXME: ideally we would want to reserve a call ID
4557 +                        * here.  current netfilter NAT core is not able to do
4558 +                        * this :( For now we use TCP source port. This breaks
4559 +                        * multiple calls within one control session */
4560 +
4561 +                       /* save original call ID in nat_info */
4562 +                       nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
4563 +
4564 +                       /* don't use tcph->source since we are at a DSTmanip
4565 +                        * hook (e.g. PREROUTING) and pkt is not mangled yet */
4566 +                       new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
4567 +
4568 +                       /* save new call ID in ct info */
4569 +                       ct_pptp_info->pns_call_id = ntohs(new_callid);
4570 +                       break;
4571 +               case PPTP_IN_CALL_REPLY:
4572 +                       cid = &pptpReq.icreq->callID;
4573 +                       break;
4574 +               case PPTP_CALL_CLEAR_REQUEST:
4575 +                       cid = &pptpReq.clrreq->callID;
4576 +                       break;
4577 +               default:
4578 +                       DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
4579 +                             (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
4580 +                       /* fall through */
4581 +
4582 +               case PPTP_SET_LINK_INFO:
4583 +                       /* only need to NAT in case PAC is behind NAT box */
4584 +               case PPTP_START_SESSION_REQUEST:
4585 +               case PPTP_START_SESSION_REPLY:
4586 +               case PPTP_STOP_SESSION_REQUEST:
4587 +               case PPTP_STOP_SESSION_REPLY:
4588 +               case PPTP_ECHO_REQUEST:
4589 +               case PPTP_ECHO_REPLY:
4590 +                       /* no need to alter packet */
4591 +                       return NF_ACCEPT;
4592 +       }
4593 +
4594 +       IP_NF_ASSERT(cid);
4595 +
4596 +       DEBUGP("altering call id from 0x%04x to 0x%04x\n",
4597 +               ntohs(*cid), ntohs(new_callid));
4598 +
4599 +       /* mangle packet */
4600 +       ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
4601 +                                sizeof(new_callid), (char *)&new_callid,
4602 +                                sizeof(new_callid));
4603 +
4604 +       return NF_ACCEPT;
4605 +}
4606 +
4607 +/* inbound packets == from PAC to PNS */
4608 +static inline unsigned int
4609 +pptp_inbound_pkt(struct sk_buff **pskb,
4610 +                struct ip_conntrack *ct,
4611 +                enum ip_conntrack_info ctinfo,
4612 +                struct ip_conntrack_expect *oldexp)
4613 +{
4614 +       struct iphdr *iph = (*pskb)->nh.iph;
4615 +       struct tcphdr *tcph = (void *) iph + iph->ihl*4;
4616 +       struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) 
4617 +                                       ((void *)tcph + tcph->doff*4);
4618 +
4619 +       struct PptpControlHeader *ctlh;
4620 +       union pptp_ctrl_union pptpReq;
4621 +       struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
4622 +       struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
4623 +
4624 +       u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
4625 +       u_int32_t old_dst_ip;
4626 +
4627 +       struct ip_conntrack_tuple t, inv_t;
4628 +       struct ip_conntrack_tuple *orig_t, *reply_t;
4629 +
4630 +       /* FIXME: size checks !!! */
4631 +       ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
4632 +       pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
4633 +
4634 +       new_pcid = htons(nat_pptp_info->pns_call_id);
4635 +
4636 +       switch (msg = ntohs(ctlh->messageType)) {
4637 +       case PPTP_OUT_CALL_REPLY:
4638 +               pcid = &pptpReq.ocack->peersCallID;     
4639 +               cid = &pptpReq.ocack->callID;
4640 +               if (!oldexp) {
4641 +                       DEBUGP("outcall but no expectation\n");
4642 +                       break;
4643 +               }
4644 +               old_dst_ip = oldexp->tuple.dst.ip;
4645 +               t = oldexp->tuple;
4646 +               invert_tuplepr(&inv_t, &t);
4647 +
4648 +               /* save original PAC call ID in nat_info */
4649 +               nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
4650 +
4651 +               /* alter expectation */
4652 +               orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
4653 +               reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
4654 +               if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
4655 +                       /* expectation for PNS->PAC direction */
4656 +                       t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
4657 +                       t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
4658 +                       inv_t.src.ip = reply_t->src.ip;
4659 +                       inv_t.dst.ip = reply_t->dst.ip;
4660 +                       inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
4661 +                       inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
4662 +               } else {
4663 +                       /* expectation for PAC->PNS direction */
4664 +                       t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
4665 +                       t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
4666 +                       inv_t.src.ip = orig_t->src.ip;
4667 +                       inv_t.dst.ip = orig_t->dst.ip;
4668 +                       inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
4669 +                       inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
4670 +               }
4671 +
4672 +               if (!ip_conntrack_change_expect(oldexp, &t)) {
4673 +                       DEBUGP("successfully changed expect\n");
4674 +               } else {
4675 +                       DEBUGP("can't change expect\n");
4676 +               }
4677 +               ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t);
4678 +               ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t);
4679 +               break;
4680 +       case PPTP_IN_CALL_CONNECT:
4681 +               pcid = &pptpReq.iccon->peersCallID;
4682 +               if (!oldexp)
4683 +                       break;
4684 +               old_dst_ip = oldexp->tuple.dst.ip;
4685 +               t = oldexp->tuple;
4686 +
4687 +               /* alter expectation, no need for callID */
4688 +               if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
4689 +                       /* expectation for PNS->PAC direction */
4690 +                       t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
4691 +               } else {
4692 +                       /* expectation for PAC->PNS direction */
4693 +                       t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
4694 +               }
4695 +
4696 +               if (!ip_conntrack_change_expect(oldexp, &t)) {
4697 +                       DEBUGP("successfully changed expect\n");
4698 +               } else {
4699 +                       DEBUGP("can't change expect\n");
4700 +               }
4701 +               break;
4702 +       case PPTP_IN_CALL_REQUEST:
4703 +               /* only need to nat in case PAC is behind NAT box */
4704 +               break;
4705 +       case PPTP_WAN_ERROR_NOTIFY:
4706 +               pcid = &pptpReq.wanerr->peersCallID;
4707 +               break;
4708 +       case PPTP_CALL_DISCONNECT_NOTIFY:
4709 +               pcid = &pptpReq.disc->callID;
4710 +               break;
4711 +
4712 +       default:
4713 +               DEBUGP("unknown inbound packet %s\n",
4714 +                       (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
4715 +               /* fall through */
4716 +
4717 +       case PPTP_START_SESSION_REQUEST:
4718 +       case PPTP_START_SESSION_REPLY:
4719 +       case PPTP_STOP_SESSION_REQUEST:
4720 +       case PPTP_STOP_SESSION_REPLY:
4721 +       case PPTP_ECHO_REQUEST:
4722 +       case PPTP_ECHO_REPLY:
4723 +               /* no need to alter packet */
4724 +               return NF_ACCEPT;
4725 +       }
4726 +
4727 +       /* mangle packet */
4728 +       IP_NF_ASSERT(pcid);
4729 +       DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
4730 +               ntohs(*pcid), ntohs(new_pcid));
4731 +       ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
4732 +                                sizeof(new_pcid), (char *)&new_pcid, 
4733 +                                sizeof(new_pcid));
4734 +
4735 +       if (new_cid) {
4736 +               IP_NF_ASSERT(cid);
4737 +               DEBUGP("altering call id from 0x%04x to 0x%04x\n",
4738 +                       ntohs(*cid), ntohs(new_cid));
4739 +               ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, 
4740 +                                        (void *)cid - (void *)pptph, 
4741 +                                        sizeof(new_cid), (char *)&new_cid, 
4742 +                                        sizeof(new_cid));
4743 +       }
4744 +
4745 +       /* great, at least we don't need to resize packets */
4746 +       return NF_ACCEPT;
4747 +}
4748 +
4749 +
4750 +static unsigned int tcp_help(struct ip_conntrack *ct,
4751 +                            struct ip_conntrack_expect *exp,
4752 +                            struct ip_nat_info *info,
4753 +                            enum ip_conntrack_info ctinfo,
4754 +                            unsigned int hooknum, struct sk_buff **pskb)
4755 +{
4756 +       struct iphdr *iph = (*pskb)->nh.iph;
4757 +       struct tcphdr *tcph = (void *) iph + iph->ihl*4;
4758 +       unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
4759 +       struct pptp_pkt_hdr *pptph;
4760 +
4761 +       int dir;
4762 +
4763 +       DEBUGP("entering\n");
4764 +
4765 +       /* Only mangle things once: DST for original direction
4766 +          and SRC for reply direction. */
4767 +       dir = CTINFO2DIR(ctinfo);
4768 +       if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
4769 +            && dir == IP_CT_DIR_ORIGINAL)
4770 +             || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
4771 +                 && dir == IP_CT_DIR_REPLY))) {
4772 +               DEBUGP("Not touching dir %s at hook %s\n",
4773 +                      dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
4774 +                      hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
4775 +                      : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
4776 +                      : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
4777 +                      : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
4778 +               return NF_ACCEPT;
4779 +       }
4780 +
4781 +       /* if packet is too small, just skip it */
4782 +       if (datalen < sizeof(struct pptp_pkt_hdr)+
4783 +                     sizeof(struct PptpControlHeader)) {
4784 +               DEBUGP("pptp packet too short\n");
4785 +               return NF_ACCEPT;       
4786 +       }
4787 +
4788 +       pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
4789 +
4790 +       /* if it's not a control message, we can't handle it */
4791 +       if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
4792 +           ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
4793 +               DEBUGP("not a pptp control packet\n");
4794 +               return NF_ACCEPT;
4795 +       }
4796 +
4797 +       LOCK_BH(&ip_pptp_lock);
4798 +
4799 +       if (dir == IP_CT_DIR_ORIGINAL) {
4800 +               /* reuqests sent by client to server (PNS->PAC) */
4801 +               pptp_outbound_pkt(pskb, ct, ctinfo, exp);
4802 +       } else {
4803 +               /* response from the server to the client (PAC->PNS) */
4804 +               pptp_inbound_pkt(pskb, ct, ctinfo, exp);
4805 +       }
4806 +
4807 +       UNLOCK_BH(&ip_pptp_lock);
4808 +
4809 +       return NF_ACCEPT;
4810 +}
4811 +
4812 +/* nat helper struct for control connection */
4813 +static struct ip_nat_helper pptp_tcp_helper = { 
4814 +       .list = { NULL, NULL },
4815 +       .name = "pptp", 
4816 +       .flags = IP_NAT_HELPER_F_ALWAYS, 
4817 +       .me = THIS_MODULE,
4818 +       .tuple = { .src = { .ip = 0, 
4819 +                           .u = { .tcp = { .port = 
4820 +                                       __constant_htons(PPTP_CONTROL_PORT) } 
4821 +                                } 
4822 +                         },
4823 +                  .dst = { .ip = 0, 
4824 +                           .u = { .all = 0 }, 
4825 +                           .protonum = IPPROTO_TCP 
4826 +                         } 
4827 +                },
4828 +
4829 +       .mask = { .src = { .ip = 0, 
4830 +                          .u = { .tcp = { .port = 0xFFFF } } 
4831 +                        },
4832 +                 .dst = { .ip = 0, 
4833 +                          .u = { .all = 0 }, 
4834 +                          .protonum = 0xFFFF 
4835 +                        } 
4836 +               },
4837 +       .help = tcp_help, 
4838 +       .expect = pptp_nat_expected 
4839 +};
4840 +
4841 +                         
4842 +static int __init init(void)
4843 +{
4844 +       DEBUGP("%s: registering NAT helper\n", __FILE__);
4845 +       if (ip_nat_helper_register(&pptp_tcp_helper)) {
4846 +               printk(KERN_ERR "Unable to register NAT application helper "
4847 +                               "for pptp\n");
4848 +               return -EIO;
4849 +       }
4850 +
4851 +       printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
4852 +       return 0;
4853 +}
4854 +
4855 +static void __exit fini(void)
4856 +{
4857 +       DEBUGP("cleanup_module\n" );
4858 +       ip_nat_helper_unregister(&pptp_tcp_helper);
4859 +       printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
4860 +}
4861 +
4862 +module_init(init);
4863 +module_exit(fini);
4864 diff -uNr linux_org/net/ipv4/netfilter/ip_nat_proto_gre.c linux/net/ipv4/netfilter/ip_nat_proto_gre.c
4865 --- linux_org/net/ipv4/netfilter/ip_nat_proto_gre.c     1970-01-01 01:00:00.000000000 +0100
4866 +++ linux/net/ipv4/netfilter/ip_nat_proto_gre.c 2006-10-27 14:11:52.000000000 +0200
4867 @@ -0,0 +1,225 @@
4868 +/*
4869 + * ip_nat_proto_gre.c - Version 1.2
4870 + *
4871 + * NAT protocol helper module for GRE.
4872 + *
4873 + * GRE is a generic encapsulation protocol, which is generally not very
4874 + * suited for NAT, as it has no protocol-specific part as port numbers.
4875 + *
4876 + * It has an optional key field, which may help us distinguishing two 
4877 + * connections between the same two hosts.
4878 + *
4879 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 
4880 + *
4881 + * PPTP is built on top of a modified version of GRE, and has a mandatory
4882 + * field called "CallID", which serves us for the same purpose as the key
4883 + * field in plain GRE.
4884 + *
4885 + * Documentation about PPTP can be found in RFC 2637
4886 + *
4887 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
4888 + *
4889 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
4890 + *
4891 + */
4892 +
4893 +#include <linux/config.h>
4894 +#include <linux/module.h>
4895 +#include <linux/ip.h>
4896 +#include <linux/netfilter_ipv4/ip_nat.h>
4897 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
4898 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
4899 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
4900 +
4901 +MODULE_LICENSE("GPL");
4902 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
4903 +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
4904 +
4905 +#if 0
4906 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
4907 +                                      ": " format, ## args)
4908 +#else
4909 +#define DEBUGP(x, args...)
4910 +#endif
4911 +
4912 +/* is key in given range between min and max */
4913 +static int
4914 +gre_in_range(const struct ip_conntrack_tuple *tuple,
4915 +            enum ip_nat_manip_type maniptype,
4916 +            const union ip_conntrack_manip_proto *min,
4917 +            const union ip_conntrack_manip_proto *max)
4918 +{
4919 +       u_int32_t key;
4920 +
4921 +       if (maniptype == IP_NAT_MANIP_SRC)
4922 +               key = tuple->src.u.gre.key;
4923 +       else
4924 +               key = tuple->dst.u.gre.key;
4925 +
4926 +       return ntohl(key) >= ntohl(min->gre.key)
4927 +               && ntohl(key) <= ntohl(max->gre.key);
4928 +}
4929 +
4930 +/* generate unique tuple ... */
4931 +static int 
4932 +gre_unique_tuple(struct ip_conntrack_tuple *tuple,
4933 +                const struct ip_nat_range *range,
4934 +                enum ip_nat_manip_type maniptype,
4935 +                const struct ip_conntrack *conntrack)
4936 +{
4937 +       u_int32_t min, i, range_size;
4938 +       u_int32_t key = 0, *keyptr;
4939 +
4940 +       if (maniptype == IP_NAT_MANIP_SRC)
4941 +               keyptr = &tuple->src.u.gre.key;
4942 +       else
4943 +               keyptr = &tuple->dst.u.gre.key;
4944 +
4945 +       if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
4946 +
4947 +               switch (tuple->dst.u.gre.version) {
4948 +               case 0:
4949 +                       DEBUGP("NATing GRE version 0 (ct=%p)\n",
4950 +                               conntrack);
4951 +                       min = 1;
4952 +                       range_size = 0xffffffff;
4953 +                       break;
4954 +               case GRE_VERSION_PPTP:
4955 +                       DEBUGP("%p: NATing GRE PPTP\n", 
4956 +                               conntrack);
4957 +                       min = 1;
4958 +                       range_size = 0xffff;
4959 +                       break;
4960 +               default:
4961 +                       printk(KERN_WARNING "nat_gre: unknown GRE version\n");
4962 +                       return 0;
4963 +                       break;
4964 +               }
4965 +
4966 +       } else {
4967 +               min = ntohl(range->min.gre.key);
4968 +               range_size = ntohl(range->max.gre.key) - min + 1;
4969 +       }
4970 +
4971 +       DEBUGP("min = %u, range_size = %u\n", min, range_size); 
4972 +
4973 +       for (i = 0; i < range_size; i++, key++) {
4974 +               *keyptr = htonl(min + key % range_size);
4975 +               if (!ip_nat_used_tuple(tuple, conntrack))
4976 +                       return 1;
4977 +       }
4978 +
4979 +       DEBUGP("%p: no NAT mapping\n", conntrack);
4980 +
4981 +       return 0;
4982 +}
4983 +
4984 +/* manipulate a GRE packet according to maniptype */
4985 +static void 
4986 +gre_manip_pkt(struct iphdr *iph, size_t len, 
4987 +             const struct ip_conntrack_manip *manip,
4988 +             enum ip_nat_manip_type maniptype)
4989 +{
4990 +       struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
4991 +       struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
4992 +
4993 +       /* we only have destination manip of a packet, since 'source key' 
4994 +        * is not present in the packet itself */
4995 +       if (maniptype == IP_NAT_MANIP_DST) {
4996 +               /* key manipulation is always dest */
4997 +               switch (greh->version) {
4998 +               case 0:
4999 +                       if (!greh->key) {
5000 +                               DEBUGP("can't nat GRE w/o key\n");
5001 +                               break;
5002 +                       }
5003 +                       if (greh->csum) {
5004 +                               /* FIXME: Never tested this code... */
5005 +                               *(gre_csum(greh)) = 
5006 +                                       ip_nat_cheat_check(~*(gre_key(greh)),
5007 +                                                       manip->u.gre.key,
5008 +                                                       *(gre_csum(greh)));
5009 +                       }
5010 +                       *(gre_key(greh)) = manip->u.gre.key;
5011 +                       break;
5012 +               case GRE_VERSION_PPTP:
5013 +                       DEBUGP("call_id -> 0x%04x\n", 
5014 +                               ntohl(manip->u.gre.key));
5015 +                       pgreh->call_id = htons(ntohl(manip->u.gre.key));
5016 +                       break;
5017 +               default:
5018 +                       DEBUGP("can't nat unknown GRE version\n");
5019 +                       break;
5020 +               }
5021 +       }
5022 +}
5023 +
5024 +/* print out a nat tuple */
5025 +static unsigned int 
5026 +gre_print(char *buffer, 
5027 +         const struct ip_conntrack_tuple *match,
5028 +         const struct ip_conntrack_tuple *mask)
5029 +{
5030 +       unsigned int len = 0;
5031 +
5032 +       if (mask->dst.u.gre.version)
5033 +               len += sprintf(buffer + len, "version=%d ",
5034 +                               ntohs(match->dst.u.gre.version));
5035 +
5036 +       if (mask->dst.u.gre.protocol)
5037 +               len += sprintf(buffer + len, "protocol=0x%x ",
5038 +                               ntohs(match->dst.u.gre.protocol));
5039 +
5040 +       if (mask->src.u.gre.key)
5041 +               len += sprintf(buffer + len, "srckey=0x%x ", 
5042 +                               ntohl(match->src.u.gre.key));
5043 +
5044 +       if (mask->dst.u.gre.key)
5045 +               len += sprintf(buffer + len, "dstkey=0x%x ",
5046 +                               ntohl(match->src.u.gre.key));
5047 +
5048 +       return len;
5049 +}
5050 +
5051 +/* print a range of keys */
5052 +static unsigned int 
5053 +gre_print_range(char *buffer, const struct ip_nat_range *range)
5054 +{
5055 +       if (range->min.gre.key != 0 
5056 +           || range->max.gre.key != 0xFFFF) {
5057 +               if (range->min.gre.key == range->max.gre.key)
5058 +                       return sprintf(buffer, "key 0x%x ",
5059 +                                       ntohl(range->min.gre.key));
5060 +               else
5061 +                       return sprintf(buffer, "keys 0x%u-0x%u ",
5062 +                                       ntohl(range->min.gre.key),
5063 +                                       ntohl(range->max.gre.key));
5064 +       } else
5065 +               return 0;
5066 +}
5067 +
5068 +/* nat helper struct */
5069 +static struct ip_nat_protocol gre = 
5070 +       { { NULL, NULL }, "GRE", IPPROTO_GRE,
5071 +         gre_manip_pkt,
5072 +         gre_in_range,
5073 +         gre_unique_tuple,
5074 +         gre_print,
5075 +         gre_print_range 
5076 +       };
5077 +                                 
5078 +static int __init init(void)
5079 +{
5080 +        if (ip_nat_protocol_register(&gre))
5081 +                return -EIO;
5082 +
5083 +        return 0;
5084 +}
5085 +
5086 +static void __exit fini(void)
5087 +{
5088 +        ip_nat_protocol_unregister(&gre);
5089 +}
5090 +
5091 +module_init(init);
5092 +module_exit(fini);