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