1 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack.h
2 ===================================================================
3 --- linux-2.4.35.4.orig/include/linux/netfilter_ipv4/ip_conntrack.h 2007-12-15 05:20:06.024183543 +0100
4 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack.h 2007-12-15 05:20:06.392204515 +0100
7 #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
8 #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
9 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
11 /* per conntrack: protocol private data */
12 union ip_conntrack_proto {
13 /* insert conntrack proto private data here */
15 struct ip_ct_icmp icmp;
16 + struct ip_ct_gre gre;
19 union ip_conntrack_expect_proto {
20 /* insert expect proto private data here */
21 + struct ip_ct_gre_expect gre;
24 /* Add protocol helper include file here */
27 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
28 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
29 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
31 /* per expectation: application helper private data */
32 union ip_conntrack_expect_help {
34 struct ip_ct_amanda_expect exp_amanda_info;
35 struct ip_ct_ftp_expect exp_ftp_info;
36 struct ip_ct_irc_expect exp_irc_info;
37 + struct ip_ct_pptp_expect exp_pptp_info;
39 #ifdef CONFIG_IP_NF_NAT_NEEDED
42 /* insert conntrack helper private data (master) here */
43 struct ip_ct_ftp_master ct_ftp_info;
44 struct ip_ct_irc_master ct_irc_info;
45 + struct ip_ct_pptp_master ct_pptp_info;
48 #ifdef CONFIG_IP_NF_NAT_NEEDED
49 #include <linux/netfilter_ipv4/ip_nat.h>
50 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
52 /* per conntrack: nat application helper private data */
53 union ip_conntrack_nat_help {
54 /* insert nat helper private data here */
55 + struct ip_nat_pptp nat_pptp_info;
59 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
60 ===================================================================
61 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
62 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2007-12-15 05:20:06.400204969 +0100
64 +/* PPTP constants and structs */
65 +#ifndef _CONNTRACK_PPTP_H
66 +#define _CONNTRACK_PPTP_H
68 +/* state of the control session */
69 +enum pptp_ctrlsess_state {
70 + PPTP_SESSION_NONE, /* no session present */
71 + PPTP_SESSION_ERROR, /* some session error */
72 + PPTP_SESSION_STOPREQ, /* stop_sess request seen */
73 + PPTP_SESSION_REQUESTED, /* start_sess request seen */
74 + PPTP_SESSION_CONFIRMED, /* session established */
77 +/* state of the call inside the control session */
78 +enum pptp_ctrlcall_state {
86 + PPTP_CALL_CLEAR_REQ,
90 +/* conntrack private data */
91 +struct ip_ct_pptp_master {
92 + enum pptp_ctrlsess_state sstate; /* session state */
94 + /* everything below is going to be per-expectation in newnat,
95 + * since there could be more than one call within one session */
96 + enum pptp_ctrlcall_state cstate; /* call state */
97 + u_int16_t pac_call_id; /* call id of PAC, host byte order */
98 + u_int16_t pns_call_id; /* call id of PNS, host byte order */
101 +/* conntrack_expect private member */
102 +struct ip_ct_pptp_expect {
103 + enum pptp_ctrlcall_state cstate; /* call state */
104 + u_int16_t pac_call_id; /* call id of PAC */
105 + u_int16_t pns_call_id; /* call id of PNS */
111 +#include <linux/netfilter_ipv4/lockhelp.h>
112 +DECLARE_LOCK_EXTERN(ip_pptp_lock);
114 +#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
116 +union pptp_ctrl_union {
118 + struct PptpStartSessionRequest *sreq;
119 + struct PptpStartSessionReply *srep;
120 + struct PptpStopSessionRequest *streq;
121 + struct PptpStopSessionReply *strep;
122 + struct PptpOutCallRequest *ocreq;
123 + struct PptpOutCallReply *ocack;
124 + struct PptpInCallRequest *icreq;
125 + struct PptpInCallReply *icack;
126 + struct PptpInCallConnected *iccon;
127 + struct PptpClearCallRequest *clrreq;
128 + struct PptpCallDisconnectNotify *disc;
129 + struct PptpWanErrorNotify *wanerr;
130 + struct PptpSetLinkInfo *setlink;
135 +#define PPTP_CONTROL_PORT 1723
137 +#define PPTP_PACKET_CONTROL 1
138 +#define PPTP_PACKET_MGMT 2
140 +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d
142 +struct pptp_pkt_hdr {
143 + __u16 packetLength;
148 +/* PptpControlMessageType values */
149 +#define PPTP_START_SESSION_REQUEST 1
150 +#define PPTP_START_SESSION_REPLY 2
151 +#define PPTP_STOP_SESSION_REQUEST 3
152 +#define PPTP_STOP_SESSION_REPLY 4
153 +#define PPTP_ECHO_REQUEST 5
154 +#define PPTP_ECHO_REPLY 6
155 +#define PPTP_OUT_CALL_REQUEST 7
156 +#define PPTP_OUT_CALL_REPLY 8
157 +#define PPTP_IN_CALL_REQUEST 9
158 +#define PPTP_IN_CALL_REPLY 10
159 +#define PPTP_IN_CALL_CONNECT 11
160 +#define PPTP_CALL_CLEAR_REQUEST 12
161 +#define PPTP_CALL_DISCONNECT_NOTIFY 13
162 +#define PPTP_WAN_ERROR_NOTIFY 14
163 +#define PPTP_SET_LINK_INFO 15
165 +#define PPTP_MSG_MAX 15
167 +/* PptpGeneralError values */
168 +#define PPTP_ERROR_CODE_NONE 0
169 +#define PPTP_NOT_CONNECTED 1
170 +#define PPTP_BAD_FORMAT 2
171 +#define PPTP_BAD_VALUE 3
172 +#define PPTP_NO_RESOURCE 4
173 +#define PPTP_BAD_CALLID 5
174 +#define PPTP_REMOVE_DEVICE_ERROR 6
176 +struct PptpControlHeader {
181 +/* FramingCapability Bitmap Values */
182 +#define PPTP_FRAME_CAP_ASYNC 0x1
183 +#define PPTP_FRAME_CAP_SYNC 0x2
185 +/* BearerCapability Bitmap Values */
186 +#define PPTP_BEARER_CAP_ANALOG 0x1
187 +#define PPTP_BEARER_CAP_DIGITAL 0x2
189 +struct PptpStartSessionRequest {
190 + __u16 protocolVersion;
193 + __u32 framingCapability;
194 + __u32 bearerCapability;
196 + __u16 firmwareRevision;
198 + __u8 vendorString[64];
201 +/* PptpStartSessionResultCode Values */
202 +#define PPTP_START_OK 1
203 +#define PPTP_START_GENERAL_ERROR 2
204 +#define PPTP_START_ALREADY_CONNECTED 3
205 +#define PPTP_START_NOT_AUTHORIZED 4
206 +#define PPTP_START_UNKNOWN_PROTOCOL 5
208 +struct PptpStartSessionReply {
209 + __u16 protocolVersion;
211 + __u8 generalErrorCode;
212 + __u32 framingCapability;
213 + __u32 bearerCapability;
215 + __u16 firmwareRevision;
217 + __u8 vendorString[64];
220 +/* PptpStopReasons */
221 +#define PPTP_STOP_NONE 1
222 +#define PPTP_STOP_PROTOCOL 2
223 +#define PPTP_STOP_LOCAL_SHUTDOWN 3
225 +struct PptpStopSessionRequest {
229 +/* PptpStopSessionResultCode */
230 +#define PPTP_STOP_OK 1
231 +#define PPTP_STOP_GENERAL_ERROR 2
233 +struct PptpStopSessionReply {
235 + __u8 generalErrorCode;
238 +struct PptpEchoRequest {
242 +/* PptpEchoReplyResultCode */
243 +#define PPTP_ECHO_OK 1
244 +#define PPTP_ECHO_GENERAL_ERROR 2
246 +struct PptpEchoReply {
249 + __u8 generalErrorCode;
253 +/* PptpFramingType */
254 +#define PPTP_ASYNC_FRAMING 1
255 +#define PPTP_SYNC_FRAMING 2
256 +#define PPTP_DONT_CARE_FRAMING 3
258 +/* PptpCallBearerType */
259 +#define PPTP_ANALOG_TYPE 1
260 +#define PPTP_DIGITAL_TYPE 2
261 +#define PPTP_DONT_CARE_BEARER_TYPE 3
263 +struct PptpOutCallRequest {
265 + __u16 callSerialNumber;
270 + __u16 packetWindow;
271 + __u16 packetProcDelay;
273 + __u16 phoneNumberLength;
275 + __u8 phoneNumber[64];
276 + __u8 subAddress[64];
279 +/* PptpCallResultCode */
280 +#define PPTP_OUTCALL_CONNECT 1
281 +#define PPTP_OUTCALL_GENERAL_ERROR 2
282 +#define PPTP_OUTCALL_NO_CARRIER 3
283 +#define PPTP_OUTCALL_BUSY 4
284 +#define PPTP_OUTCALL_NO_DIAL_TONE 5
285 +#define PPTP_OUTCALL_TIMEOUT 6
286 +#define PPTP_OUTCALL_DONT_ACCEPT 7
288 +struct PptpOutCallReply {
292 + __u8 generalErrorCode;
294 + __u32 connectSpeed;
295 + __u16 packetWindow;
296 + __u16 packetProcDelay;
297 + __u32 physChannelID;
300 +struct PptpInCallRequest {
302 + __u16 callSerialNumber;
303 + __u32 callBearerType;
304 + __u32 physChannelID;
305 + __u16 dialedNumberLength;
306 + __u16 dialingNumberLength;
307 + __u8 dialedNumber[64];
308 + __u8 dialingNumber[64];
309 + __u8 subAddress[64];
312 +/* PptpInCallResultCode */
313 +#define PPTP_INCALL_ACCEPT 1
314 +#define PPTP_INCALL_GENERAL_ERROR 2
315 +#define PPTP_INCALL_DONT_ACCEPT 3
317 +struct PptpInCallReply {
321 + __u8 generalErrorCode;
322 + __u16 packetWindow;
323 + __u16 packetProcDelay;
327 +struct PptpInCallConnected {
330 + __u32 connectSpeed;
331 + __u16 packetWindow;
332 + __u16 packetProcDelay;
333 + __u32 callFramingType;
336 +struct PptpClearCallRequest {
341 +struct PptpCallDisconnectNotify {
344 + __u8 generalErrorCode;
347 + __u8 callStatistics[128];
350 +struct PptpWanErrorNotify {
354 + __u32 framingErrors;
355 + __u32 hardwareOverRuns;
356 + __u32 bufferOverRuns;
357 + __u32 timeoutErrors;
358 + __u32 alignmentErrors;
361 +struct PptpSetLinkInfo {
369 +struct pptp_priv_data {
375 +#endif /* __KERNEL__ */
376 +#endif /* _CONNTRACK_PPTP_H */
377 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
378 ===================================================================
379 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
380 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2007-12-15 05:20:06.400204969 +0100
382 +#ifndef _CONNTRACK_PROTO_GRE_H
383 +#define _CONNTRACK_PROTO_GRE_H
384 +#include <asm/byteorder.h>
386 +/* GRE PROTOCOL HEADER */
388 +/* GRE Version field */
389 +#define GRE_VERSION_1701 0x0
390 +#define GRE_VERSION_PPTP 0x1
392 +/* GRE Protocol field */
393 +#define GRE_PROTOCOL_PPTP 0x880B
396 +#define GRE_FLAG_C 0x80
397 +#define GRE_FLAG_R 0x40
398 +#define GRE_FLAG_K 0x20
399 +#define GRE_FLAG_S 0x10
400 +#define GRE_FLAG_A 0x80
402 +#define GRE_IS_C(f) ((f)&GRE_FLAG_C)
403 +#define GRE_IS_R(f) ((f)&GRE_FLAG_R)
404 +#define GRE_IS_K(f) ((f)&GRE_FLAG_K)
405 +#define GRE_IS_S(f) ((f)&GRE_FLAG_S)
406 +#define GRE_IS_A(f) ((f)&GRE_FLAG_A)
408 +/* GRE is a mess: Four different standards */
410 +#if defined(__LITTLE_ENDIAN_BITFIELD)
420 +#elif defined(__BIG_ENDIAN_BITFIELD)
431 +#error "Adjust your <asm/byteorder.h> defines"
436 +/* modified GRE header for PPTP */
437 +struct gre_hdr_pptp {
438 + __u8 flags; /* bitfield */
439 + __u8 version; /* should be GRE_VERSION_PPTP */
440 + __u16 protocol; /* should be GRE_PROTOCOL_PPTP */
441 + __u16 payload_len; /* size of ppp payload, not inc. gre header */
442 + __u16 call_id; /* peer's call_id for this session */
443 + __u32 seq; /* sequence number. Present if S==1 */
444 + __u32 ack; /* seq number of highest packet recieved by */
445 + /* sender in this session */
449 +/* this is part of ip_conntrack */
451 + unsigned int stream_timeout;
452 + unsigned int timeout;
455 +/* this is part of ip_conntrack_expect */
456 +struct ip_ct_gre_expect {
457 + struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
461 +struct ip_conntrack_expect;
463 +/* structure for original <-> reply keymap */
464 +struct ip_ct_gre_keymap {
465 + struct list_head list;
467 + struct ip_conntrack_tuple tuple;
471 +/* add new tuple->key_reply pair to keymap */
472 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
473 + struct ip_conntrack_tuple *t,
476 +/* change an existing keymap entry */
477 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
478 + struct ip_conntrack_tuple *t);
480 +/* delete keymap entries */
481 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
484 +/* get pointer to gre key, if present */
485 +static inline u_int32_t *gre_key(struct gre_hdr *greh)
489 + if (greh->csum || greh->routing)
490 + return (u_int32_t *) (greh+sizeof(*greh)+4);
491 + return (u_int32_t *) (greh+sizeof(*greh));
494 +/* get pointer ot gre csum, if present */
495 +static inline u_int16_t *gre_csum(struct gre_hdr *greh)
499 + return (u_int16_t *) (greh+sizeof(*greh));
502 +#endif /* __KERNEL__ */
504 +#endif /* _CONNTRACK_PROTO_GRE_H */
505 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
506 ===================================================================
507 --- linux-2.4.35.4.orig/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2007-12-15 05:19:38.250600816 +0100
508 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2007-12-15 05:20:06.400204969 +0100
510 union ip_conntrack_manip_proto
512 /* Add other protocols here. */
527 /* The manipulable part of the tuple. */
531 /* Add other protocols here. */
550 #define DUMP_TUPLE(tp) \
551 -DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
552 +DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \
553 (tp), (tp)->dst.protonum, \
554 - NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
555 - NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
556 + NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \
557 + NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all))
559 +#define DUMP_TUPLE_RAW(x) \
560 + DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\
561 + (x), (x)->dst.protonum, \
562 + NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \
563 + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all))
565 #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
567 Index: linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat_pptp.h
568 ===================================================================
569 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
570 +++ linux-2.4.35.4/include/linux/netfilter_ipv4/ip_nat_pptp.h 2007-12-15 05:20:06.400204969 +0100
572 +/* PPTP constants and structs */
576 +/* conntrack private data */
577 +struct ip_nat_pptp {
578 + u_int16_t pns_call_id; /* NAT'ed PNS call id */
579 + u_int16_t pac_call_id; /* NAT'ed PAC call id */
582 +#endif /* _NAT_PPTP_H */
583 Index: linux-2.4.35.4/net/ipv4/netfilter/Config.in
584 ===================================================================
585 --- linux-2.4.35.4.orig/net/ipv4/netfilter/Config.in 2007-12-15 05:20:06.036184227 +0100
586 +++ linux-2.4.35.4/net/ipv4/netfilter/Config.in 2007-12-15 05:20:06.400204969 +0100
588 dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
589 dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
590 dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
591 + dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
592 + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
595 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
597 define_bool CONFIG_IP_NF_NAT_NEEDED y
598 dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
599 dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
600 + if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then
601 + define_tristate CONFIG_IP_NF_NAT_PPTP m
603 + if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then
604 + define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT
607 + if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then
608 + define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m
610 + if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then
611 + define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
614 if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then
615 define_tristate CONFIG_IP_NF_NAT_AMANDA m
617 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_core.c
618 ===================================================================
619 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_conntrack_core.c 2007-12-15 05:20:06.036184227 +0100
620 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_core.c 2007-12-15 05:20:06.404205198 +0100
622 tuple->dst.ip = iph->daddr;
623 tuple->dst.protonum = iph->protocol;
625 + tuple->src.u.all = tuple->dst.u.all = 0;
627 ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
631 inverse->dst.ip = orig->src.ip;
632 inverse->dst.protonum = orig->dst.protonum;
634 + inverse->src.u.all = inverse->dst.u.all = 0;
636 return protocol->invert_tuple(inverse, orig);
640 * so there is no need to use the tuple lock too */
642 DEBUGP("ip_conntrack_expect_related %p\n", related_to);
643 - DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
644 - DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
645 + DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
646 + DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask);
648 old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
649 struct ip_conntrack_expect *, &expect->tuple,
650 @@ -1089,15 +1093,14 @@
652 MUST_BE_READ_LOCKED(&ip_conntrack_lock);
653 WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
655 DEBUGP("change_expect:\n");
656 - DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
657 - DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
658 - DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
659 + DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
660 + DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask);
661 + DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple);
662 if (expect->ct_tuple.dst.protonum == 0) {
663 /* Never seen before */
664 DEBUGP("change expect: never seen before\n");
665 - if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
666 + if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
667 && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
668 struct ip_conntrack_expect *, newtuple, &expect->mask)) {
669 /* Force NAT to find an unused tuple */
670 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
671 ===================================================================
672 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
673 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2007-12-15 05:20:06.404205198 +0100
675 +#ifndef _IP_CT_PPTP_PRIV_H
676 +#define _IP_CT_PPTP_PRIV_H
678 +/* PptpControlMessageType names */
679 +static const char *strMName[] = {
681 + "START_SESSION_REQUEST",
682 + "START_SESSION_REPLY",
683 + "STOP_SESSION_REQUEST",
684 + "STOP_SESSION_REPLY",
687 + "OUT_CALL_REQUEST",
692 + "CALL_CLEAR_REQUEST",
693 + "CALL_DISCONNECT_NOTIFY",
694 + "WAN_ERROR_NOTIFY",
699 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_proto_gre.c
700 ===================================================================
701 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
702 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2007-12-15 05:20:06.404205198 +0100
705 + * ip_conntrack_proto_gre.c - Version 1.2
707 + * Connection tracking protocol helper module for GRE.
709 + * GRE is a generic encapsulation protocol, which is generally not very
710 + * suited for NAT, as it has no protocol-specific part as port numbers.
712 + * It has an optional key field, which may help us distinguishing two
713 + * connections between the same two hosts.
715 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
717 + * PPTP is built on top of a modified version of GRE, and has a mandatory
718 + * field called "CallID", which serves us for the same purpose as the key
719 + * field in plain GRE.
721 + * Documentation about PPTP can be found in RFC 2637
723 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
725 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
729 +#include <linux/config.h>
730 +#include <linux/module.h>
731 +#include <linux/types.h>
732 +#include <linux/timer.h>
733 +#include <linux/netfilter.h>
734 +#include <linux/ip.h>
735 +#include <linux/in.h>
736 +#include <linux/list.h>
738 +#include <linux/netfilter_ipv4/lockhelp.h>
740 +DECLARE_RWLOCK(ip_ct_gre_lock);
741 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
742 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
744 +#include <linux/netfilter_ipv4/listhelp.h>
745 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
746 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
747 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
749 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
750 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
752 +MODULE_LICENSE("GPL");
753 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
754 +MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
756 +/* shamelessly stolen from ip_conntrack_proto_udp.c */
757 +#define GRE_TIMEOUT (30*HZ)
758 +#define GRE_STREAM_TIMEOUT (180*HZ)
761 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
762 + ": " format, ## args)
763 +#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
764 + NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
765 + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key))
767 +#define DEBUGP(x, args...)
768 +#define DUMP_TUPLE_GRE(x)
771 +/* GRE KEYMAP HANDLING FUNCTIONS */
772 +static LIST_HEAD(gre_keymap_list);
774 +static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
775 + const struct ip_conntrack_tuple *t)
777 + return ((km->tuple.src.ip == t->src.ip) &&
778 + (km->tuple.dst.ip == t->dst.ip) &&
779 + (km->tuple.dst.protonum == t->dst.protonum) &&
780 + (km->tuple.dst.u.all == t->dst.u.all));
783 +/* look up the source key for a given tuple */
784 +static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
786 + struct ip_ct_gre_keymap *km;
789 + READ_LOCK(&ip_ct_gre_lock);
790 + km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
791 + struct ip_ct_gre_keymap *, t);
793 + READ_UNLOCK(&ip_ct_gre_lock);
797 + key = km->tuple.src.u.gre.key;
798 + READ_UNLOCK(&ip_ct_gre_lock);
803 +/* add a single keymap entry, associate with specified expect */
804 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
805 + struct ip_conntrack_tuple *t, int reply)
807 + struct ip_ct_gre_keymap *km;
809 + km = kmalloc(sizeof(*km), GFP_ATOMIC);
813 + /* initializing list head should be sufficient */
814 + memset(km, 0, sizeof(*km));
816 + memcpy(&km->tuple, t, sizeof(*t));
819 + exp->proto.gre.keymap_orig = km;
821 + exp->proto.gre.keymap_reply = km;
823 + DEBUGP("adding new entry %p: ", km);
824 + DUMP_TUPLE_GRE(&km->tuple);
826 + WRITE_LOCK(&ip_ct_gre_lock);
827 + list_append(&gre_keymap_list, km);
828 + WRITE_UNLOCK(&ip_ct_gre_lock);
833 +/* change the tuple of a keymap entry (used by nat helper) */
834 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
835 + struct ip_conntrack_tuple *t)
837 + DEBUGP("changing entry %p to: ", km);
840 + WRITE_LOCK(&ip_ct_gre_lock);
841 + memcpy(&km->tuple, t, sizeof(km->tuple));
842 + WRITE_UNLOCK(&ip_ct_gre_lock);
845 +/* destroy the keymap entries associated with specified expect */
846 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
848 + DEBUGP("entering for exp %p\n", exp);
849 + WRITE_LOCK(&ip_ct_gre_lock);
850 + if (exp->proto.gre.keymap_orig) {
851 + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
852 + list_del(&exp->proto.gre.keymap_orig->list);
853 + kfree(exp->proto.gre.keymap_orig);
854 + exp->proto.gre.keymap_orig = NULL;
856 + if (exp->proto.gre.keymap_reply) {
857 + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
858 + list_del(&exp->proto.gre.keymap_reply->list);
859 + kfree(exp->proto.gre.keymap_reply);
860 + exp->proto.gre.keymap_reply = NULL;
862 + WRITE_UNLOCK(&ip_ct_gre_lock);
866 +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
868 +/* invert gre part of tuple */
869 +static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
870 + const struct ip_conntrack_tuple *orig)
872 + tuple->dst.u.gre.key = orig->src.u.gre.key;
873 + tuple->src.u.gre.key = orig->dst.u.gre.key;
878 +/* gre hdr info to tuple */
879 +static int gre_pkt_to_tuple(const void *datah, size_t datalen,
880 + struct ip_conntrack_tuple *tuple)
882 + struct gre_hdr *grehdr = (struct gre_hdr *) datah;
883 + struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
886 + /* core guarantees 8 protocol bytes, no need for size check */
888 + switch (grehdr->version) {
889 + case GRE_VERSION_1701:
890 + if (!grehdr->key) {
891 + DEBUGP("Can't track GRE without key\n");
894 + tuple->dst.u.gre.key = *(gre_key(grehdr));
897 + case GRE_VERSION_PPTP:
898 + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
899 + DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
902 + tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
906 + printk(KERN_WARNING "unknown GRE version %hu\n",
911 + srckey = gre_keymap_lookup(tuple);
914 + DEBUGP("found src key %x for tuple ", ntohl(srckey));
915 + DUMP_TUPLE_GRE(tuple);
917 + tuple->src.u.gre.key = srckey;
922 +/* print gre part of tuple */
923 +static unsigned int gre_print_tuple(char *buffer,
924 + const struct ip_conntrack_tuple *tuple)
926 + return sprintf(buffer, "srckey=0x%x dstkey=0x%x ",
927 + ntohl(tuple->src.u.gre.key),
928 + ntohl(tuple->dst.u.gre.key));
931 +/* print private data for conntrack */
932 +static unsigned int gre_print_conntrack(char *buffer,
933 + const struct ip_conntrack *ct)
935 + return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
936 + (ct->proto.gre.timeout / HZ),
937 + (ct->proto.gre.stream_timeout / HZ));
940 +/* Returns verdict for packet, and may modify conntrack */
941 +static int gre_packet(struct ip_conntrack *ct,
942 + struct iphdr *iph, size_t len,
943 + enum ip_conntrack_info conntrackinfo)
945 + /* If we've seen traffic both ways, this is a GRE connection.
946 + * Extend timeout. */
947 + if (ct->status & IPS_SEEN_REPLY) {
948 + ip_ct_refresh_acct(ct, ct->proto.gre.stream_timeout);
949 + /* Also, more likely to be important, and not a probe. */
950 + set_bit(IPS_ASSURED_BIT, &ct->status);
952 + ip_ct_refresh_acct(ct, ct->proto.gre.timeout);
957 +/* Called when a new connection for this protocol found. */
958 +static int gre_new(struct ip_conntrack *ct,
959 + struct iphdr *iph, size_t len)
962 + DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
964 + /* initialize to sane value. Ideally a conntrack helper
965 + * (e.g. in case of pptp) is increasing them */
966 + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
967 + ct->proto.gre.timeout = GRE_TIMEOUT;
972 +/* Called when a conntrack entry has already been removed from the hashes
973 + * and is about to be deleted from memory */
974 +static void gre_destroy(struct ip_conntrack *ct)
976 + struct ip_conntrack_expect *master = ct->master;
978 + DEBUGP(" entering\n");
981 + DEBUGP("no master exp for ct %p\n", ct);
985 + ip_ct_gre_keymap_destroy(master);
988 +/* protocol helper struct */
989 +static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
994 + gre_print_conntrack,
1001 +/* ip_conntrack_proto_gre initialization */
1002 +static int __init init(void)
1006 + if ((retcode = ip_conntrack_protocol_register(&gre))) {
1007 + printk(KERN_ERR "Unable to register conntrack protocol "
1008 + "helper for gre: %d\n", retcode);
1015 +static void __exit fini(void)
1017 + struct list_head *pos, *n;
1019 + /* delete all keymap entries */
1020 + WRITE_LOCK(&ip_ct_gre_lock);
1021 + list_for_each_safe(pos, n, &gre_keymap_list) {
1022 + DEBUGP("deleting keymap %p at module unload time\n", pos);
1026 + WRITE_UNLOCK(&ip_ct_gre_lock);
1028 + ip_conntrack_protocol_unregister(&gre);
1031 +EXPORT_SYMBOL(ip_ct_gre_keymap_add);
1032 +EXPORT_SYMBOL(ip_ct_gre_keymap_change);
1033 +EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
1037 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c
1038 ===================================================================
1039 --- linux-2.4.35.4.orig/net/ipv4/netfilter/ip_nat_core.c 2007-12-15 05:19:38.290603095 +0100
1040 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_core.c 2007-12-15 05:20:06.404205198 +0100
1042 *tuple = *orig_tuple;
1043 while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
1045 - DEBUGP("Found best for "); DUMP_TUPLE(tuple);
1046 + DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple);
1047 /* 3) The per-protocol part of the manip is made to
1048 map into the range to make a unique tuple. */
1051 HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
1053 DEBUGP("Original: ");
1054 - DUMP_TUPLE(&orig_tp);
1055 + DUMP_TUPLE_RAW(&orig_tp);
1057 - DUMP_TUPLE(&new_tuple);
1058 + DUMP_TUPLE_RAW(&new_tuple);
1061 /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
1062 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_pptp.c
1063 ===================================================================
1064 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1065 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_pptp.c 2007-12-15 05:20:06.408205428 +0100
1068 + * ip_nat_pptp.c - Version 1.5
1070 + * NAT support for PPTP (Point to Point Tunneling Protocol).
1071 + * PPTP is a a protocol for creating virtual private networks.
1072 + * It is a specification defined by Microsoft and some vendors
1073 + * working with Microsoft. PPTP is built on top of a modified
1074 + * version of the Internet Generic Routing Encapsulation Protocol.
1075 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of
1076 + * PPTP can be found in RFC 2637
1078 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1080 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1082 + * TODO: - Support for multiple calls within one session
1083 + * (needs netfilter newnat code)
1084 + * - NAT to a unique tuple, not to TCP source port
1085 + * (needs netfilter tuple reservation)
1088 + * 2002-02-10 - Version 1.3
1089 + * - Use ip_nat_mangle_tcp_packet() because of cloned skb's
1090 + * in local connections (Philip Craig <philipc@snapgear.com>)
1091 + * - add checks for magicCookie and pptp version
1092 + * - make argument list of pptp_{out,in}bound_packet() shorter
1093 + * - move to C99 style initializers
1094 + * - print version number at module loadtime
1095 + * 2003-09-22 - Version 1.5
1096 + * - use SNATed tcp sourceport as callid, since we get called before
1097 + * TCP header is mangled (Philip Craig <philipc@snapgear.com>)
1101 +#include <linux/config.h>
1102 +#include <linux/module.h>
1103 +#include <linux/ip.h>
1104 +#include <linux/tcp.h>
1105 +#include <net/tcp.h>
1106 +#include <linux/netfilter_ipv4/ip_nat.h>
1107 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
1108 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
1109 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
1110 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1111 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1112 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1114 +#define IP_NAT_PPTP_VERSION "1.5"
1116 +MODULE_LICENSE("GPL");
1117 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1118 +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
1122 +#include "ip_conntrack_pptp_priv.h"
1123 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1124 + ": " format, ## args)
1126 +#define DEBUGP(format, args...)
1129 +static unsigned int
1130 +pptp_nat_expected(struct sk_buff **pskb,
1131 + unsigned int hooknum,
1132 + struct ip_conntrack *ct,
1133 + struct ip_nat_info *info)
1135 + struct ip_conntrack *master = master_ct(ct);
1136 + struct ip_nat_multi_range mr;
1137 + struct ip_ct_pptp_master *ct_pptp_info;
1138 + struct ip_nat_pptp *nat_pptp_info;
1139 + u_int32_t newip, newcid;
1142 + IP_NF_ASSERT(info);
1143 + IP_NF_ASSERT(master);
1144 + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
1146 + DEBUGP("we have a connection!\n");
1148 + LOCK_BH(&ip_pptp_lock);
1149 + ct_pptp_info = &master->help.ct_pptp_info;
1150 + nat_pptp_info = &master->nat.help.nat_pptp_info;
1152 + /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
1153 + * (unmanipulated) values */
1154 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
1155 + DEBUGP("completing tuples with NAT info \n");
1156 + /* we can do this, since we're unconfirmed */
1157 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1158 + htonl(ct_pptp_info->pac_call_id)) {
1159 + /* assume PNS->PAC */
1160 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1161 + htonl(nat_pptp_info->pns_call_id);
1162 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1163 + htonl(nat_pptp_info->pns_call_id);
1164 + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
1165 + newcid = htonl(nat_pptp_info->pac_call_id);
1167 + /* assume PAC->PNS */
1168 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1169 + htonl(nat_pptp_info->pac_call_id);
1170 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1171 + htonl(nat_pptp_info->pac_call_id);
1172 + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1173 + newcid = htonl(nat_pptp_info->pns_call_id);
1176 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1177 + htonl(ct_pptp_info->pac_call_id)) {
1178 + /* assume PNS->PAC */
1179 + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1180 + newcid = htonl(ct_pptp_info->pns_call_id);
1183 + /* assume PAC->PNS */
1184 + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
1185 + newcid = htonl(ct_pptp_info->pac_call_id);
1190 + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
1191 + mr.range[0].min_ip = mr.range[0].max_ip = newip;
1192 + mr.range[0].min = mr.range[0].max =
1193 + ((union ip_conntrack_manip_proto ) { newcid });
1194 + DEBUGP("change ip to %u.%u.%u.%u\n",
1196 + DEBUGP("change key to 0x%x\n", ntohl(newcid));
1197 + ret = ip_nat_setup_info(ct, &mr, hooknum);
1199 + UNLOCK_BH(&ip_pptp_lock);
1205 +/* outbound packets == from PNS to PAC */
1206 +static inline unsigned int
1207 +pptp_outbound_pkt(struct sk_buff **pskb,
1208 + struct ip_conntrack *ct,
1209 + enum ip_conntrack_info ctinfo,
1210 + struct ip_conntrack_expect *exp)
1213 + struct iphdr *iph = (*pskb)->nh.iph;
1214 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1215 + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
1216 + ((void *)tcph + tcph->doff*4);
1218 + struct PptpControlHeader *ctlh;
1219 + union pptp_ctrl_union pptpReq;
1220 + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
1221 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
1223 + u_int16_t msg, *cid = NULL, new_callid;
1225 + /* FIXME: size checks !!! */
1226 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
1227 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
1229 + new_callid = htons(ct_pptp_info->pns_call_id);
1231 + switch (msg = ntohs(ctlh->messageType)) {
1232 + case PPTP_OUT_CALL_REQUEST:
1233 + cid = &pptpReq.ocreq->callID;
1234 + /* FIXME: ideally we would want to reserve a call ID
1235 + * here. current netfilter NAT core is not able to do
1236 + * this :( For now we use TCP source port. This breaks
1237 + * multiple calls within one control session */
1239 + /* save original call ID in nat_info */
1240 + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
1242 + /* don't use tcph->source since we are at a DSTmanip
1243 + * hook (e.g. PREROUTING) and pkt is not mangled yet */
1244 + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
1246 + /* save new call ID in ct info */
1247 + ct_pptp_info->pns_call_id = ntohs(new_callid);
1249 + case PPTP_IN_CALL_REPLY:
1250 + cid = &pptpReq.icreq->callID;
1252 + case PPTP_CALL_CLEAR_REQUEST:
1253 + cid = &pptpReq.clrreq->callID;
1256 + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
1257 + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
1258 + /* fall through */
1260 + case PPTP_SET_LINK_INFO:
1261 + /* only need to NAT in case PAC is behind NAT box */
1262 + case PPTP_START_SESSION_REQUEST:
1263 + case PPTP_START_SESSION_REPLY:
1264 + case PPTP_STOP_SESSION_REQUEST:
1265 + case PPTP_STOP_SESSION_REPLY:
1266 + case PPTP_ECHO_REQUEST:
1267 + case PPTP_ECHO_REPLY:
1268 + /* no need to alter packet */
1272 + IP_NF_ASSERT(cid);
1274 + DEBUGP("altering call id from 0x%04x to 0x%04x\n",
1275 + ntohs(*cid), ntohs(new_callid));
1277 + /* mangle packet */
1278 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
1279 + sizeof(new_callid), (char *)&new_callid,
1280 + sizeof(new_callid));
1285 +/* inbound packets == from PAC to PNS */
1286 +static inline unsigned int
1287 +pptp_inbound_pkt(struct sk_buff **pskb,
1288 + struct ip_conntrack *ct,
1289 + enum ip_conntrack_info ctinfo,
1290 + struct ip_conntrack_expect *oldexp)
1292 + struct iphdr *iph = (*pskb)->nh.iph;
1293 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1294 + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
1295 + ((void *)tcph + tcph->doff*4);
1297 + struct PptpControlHeader *ctlh;
1298 + union pptp_ctrl_union pptpReq;
1299 + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
1300 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
1302 + u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
1303 + u_int32_t old_dst_ip;
1305 + struct ip_conntrack_tuple t, inv_t;
1306 + struct ip_conntrack_tuple *orig_t, *reply_t;
1308 + /* FIXME: size checks !!! */
1309 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
1310 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
1312 + new_pcid = htons(nat_pptp_info->pns_call_id);
1314 + switch (msg = ntohs(ctlh->messageType)) {
1315 + case PPTP_OUT_CALL_REPLY:
1316 + pcid = &pptpReq.ocack->peersCallID;
1317 + cid = &pptpReq.ocack->callID;
1319 + DEBUGP("outcall but no expectation\n");
1322 + old_dst_ip = oldexp->tuple.dst.ip;
1323 + t = oldexp->tuple;
1324 + invert_tuplepr(&inv_t, &t);
1326 + /* save original PAC call ID in nat_info */
1327 + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
1329 + /* alter expectation */
1330 + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
1331 + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
1332 + if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
1333 + /* expectation for PNS->PAC direction */
1334 + t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
1335 + t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
1336 + inv_t.src.ip = reply_t->src.ip;
1337 + inv_t.dst.ip = reply_t->dst.ip;
1338 + inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
1339 + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
1341 + /* expectation for PAC->PNS direction */
1342 + t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
1343 + t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
1344 + inv_t.src.ip = orig_t->src.ip;
1345 + inv_t.dst.ip = orig_t->dst.ip;
1346 + inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
1347 + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
1350 + if (!ip_conntrack_change_expect(oldexp, &t)) {
1351 + DEBUGP("successfully changed expect\n");
1353 + DEBUGP("can't change expect\n");
1355 + if (oldexp->proto.gre.keymap_orig)
1356 + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig,
1358 + if (oldexp->proto.gre.keymap_reply)
1359 + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply,
1362 + case PPTP_IN_CALL_CONNECT:
1363 + pcid = &pptpReq.iccon->peersCallID;
1366 + old_dst_ip = oldexp->tuple.dst.ip;
1367 + t = oldexp->tuple;
1369 + /* alter expectation, no need for callID */
1370 + if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
1371 + /* expectation for PNS->PAC direction */
1372 + t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1374 + /* expectation for PAC->PNS direction */
1375 + t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1378 + if (!ip_conntrack_change_expect(oldexp, &t)) {
1379 + DEBUGP("successfully changed expect\n");
1381 + DEBUGP("can't change expect\n");
1384 + case PPTP_IN_CALL_REQUEST:
1385 + /* only need to nat in case PAC is behind NAT box */
1387 + case PPTP_WAN_ERROR_NOTIFY:
1388 + pcid = &pptpReq.wanerr->peersCallID;
1390 + case PPTP_CALL_DISCONNECT_NOTIFY:
1391 + pcid = &pptpReq.disc->callID;
1393 + case PPTP_SET_LINK_INFO:
1394 + pcid = &pptpReq.setlink->peersCallID;
1398 + DEBUGP("unknown inbound packet %s\n",
1399 + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
1400 + /* fall through */
1402 + case PPTP_START_SESSION_REQUEST:
1403 + case PPTP_START_SESSION_REPLY:
1404 + case PPTP_STOP_SESSION_REQUEST:
1405 + case PPTP_STOP_SESSION_REPLY:
1406 + case PPTP_ECHO_REQUEST:
1407 + case PPTP_ECHO_REPLY:
1408 + /* no need to alter packet */
1412 + /* mangle packet */
1413 + IP_NF_ASSERT(pcid);
1414 + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
1415 + ntohs(*pcid), ntohs(new_pcid));
1416 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
1417 + sizeof(new_pcid), (char *)&new_pcid,
1418 + sizeof(new_pcid));
1421 + IP_NF_ASSERT(cid);
1422 + DEBUGP("altering call id from 0x%04x to 0x%04x\n",
1423 + ntohs(*cid), ntohs(new_cid));
1424 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
1425 + (void *)cid - (void *)pptph,
1426 + sizeof(new_cid), (char *)&new_cid,
1430 + /* great, at least we don't need to resize packets */
1435 +static unsigned int tcp_help(struct ip_conntrack *ct,
1436 + struct ip_conntrack_expect *exp,
1437 + struct ip_nat_info *info,
1438 + enum ip_conntrack_info ctinfo,
1439 + unsigned int hooknum, struct sk_buff **pskb)
1441 + struct iphdr *iph = (*pskb)->nh.iph;
1442 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1443 + unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
1444 + struct pptp_pkt_hdr *pptph;
1448 + DEBUGP("entering\n");
1450 + /* Only mangle things once: DST for original direction
1451 + and SRC for reply direction. */
1452 + dir = CTINFO2DIR(ctinfo);
1453 + if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
1454 + && dir == IP_CT_DIR_ORIGINAL)
1455 + || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
1456 + && dir == IP_CT_DIR_REPLY))) {
1457 + DEBUGP("Not touching dir %s at hook %s\n",
1458 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
1459 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
1460 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
1461 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
1462 + : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
1466 + /* if packet is too small, just skip it */
1467 + if (datalen < sizeof(struct pptp_pkt_hdr)+
1468 + sizeof(struct PptpControlHeader)) {
1469 + DEBUGP("pptp packet too short\n");
1473 + pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
1475 + /* if it's not a control message, we can't handle it */
1476 + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
1477 + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
1478 + DEBUGP("not a pptp control packet\n");
1482 + LOCK_BH(&ip_pptp_lock);
1484 + if (dir == IP_CT_DIR_ORIGINAL) {
1485 + /* reuqests sent by client to server (PNS->PAC) */
1486 + pptp_outbound_pkt(pskb, ct, ctinfo, exp);
1488 + /* response from the server to the client (PAC->PNS) */
1489 + pptp_inbound_pkt(pskb, ct, ctinfo, exp);
1492 + UNLOCK_BH(&ip_pptp_lock);
1497 +/* nat helper struct for control connection */
1498 +static struct ip_nat_helper pptp_tcp_helper = {
1499 + .list = { NULL, NULL },
1501 + .flags = IP_NAT_HELPER_F_ALWAYS,
1502 + .me = THIS_MODULE,
1503 + .tuple = { .src = { .ip = 0,
1504 + .u = { .tcp = { .port =
1505 + __constant_htons(PPTP_CONTROL_PORT) }
1509 + .u = { .all = 0 },
1510 + .protonum = IPPROTO_TCP
1514 + .mask = { .src = { .ip = 0,
1515 + .u = { .tcp = { .port = 0xFFFF } }
1518 + .u = { .all = 0 },
1519 + .protonum = 0xFFFF
1523 + .expect = pptp_nat_expected
1527 +static int __init init(void)
1529 + DEBUGP("%s: registering NAT helper\n", __FILE__);
1530 + if (ip_nat_helper_register(&pptp_tcp_helper)) {
1531 + printk(KERN_ERR "Unable to register NAT application helper "
1536 + printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
1540 +static void __exit fini(void)
1542 + DEBUGP("cleanup_module\n" );
1543 + ip_nat_helper_unregister(&pptp_tcp_helper);
1544 + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
1549 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_nat_proto_gre.c
1550 ===================================================================
1551 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1552 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_nat_proto_gre.c 2007-12-15 05:20:06.408205428 +0100
1555 + * ip_nat_proto_gre.c - Version 1.2
1557 + * NAT protocol helper module for GRE.
1559 + * GRE is a generic encapsulation protocol, which is generally not very
1560 + * suited for NAT, as it has no protocol-specific part as port numbers.
1562 + * It has an optional key field, which may help us distinguishing two
1563 + * connections between the same two hosts.
1565 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
1567 + * PPTP is built on top of a modified version of GRE, and has a mandatory
1568 + * field called "CallID", which serves us for the same purpose as the key
1569 + * field in plain GRE.
1571 + * Documentation about PPTP can be found in RFC 2637
1573 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1575 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1579 +#include <linux/config.h>
1580 +#include <linux/module.h>
1581 +#include <linux/ip.h>
1582 +#include <linux/netfilter_ipv4/ip_nat.h>
1583 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
1584 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
1585 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1587 +MODULE_LICENSE("GPL");
1588 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1589 +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
1592 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1593 + ": " format, ## args)
1595 +#define DEBUGP(x, args...)
1598 +/* is key in given range between min and max */
1600 +gre_in_range(const struct ip_conntrack_tuple *tuple,
1601 + enum ip_nat_manip_type maniptype,
1602 + const union ip_conntrack_manip_proto *min,
1603 + const union ip_conntrack_manip_proto *max)
1607 + if (maniptype == IP_NAT_MANIP_SRC)
1608 + key = tuple->src.u.gre.key;
1610 + key = tuple->dst.u.gre.key;
1612 + return ntohl(key) >= ntohl(min->gre.key)
1613 + && ntohl(key) <= ntohl(max->gre.key);
1616 +/* generate unique tuple ... */
1618 +gre_unique_tuple(struct ip_conntrack_tuple *tuple,
1619 + const struct ip_nat_range *range,
1620 + enum ip_nat_manip_type maniptype,
1621 + const struct ip_conntrack *conntrack)
1623 + u_int32_t min, i, range_size;
1624 + u_int32_t key = 0, *keyptr;
1626 + if (maniptype == IP_NAT_MANIP_SRC)
1627 + keyptr = &tuple->src.u.gre.key;
1629 + keyptr = &tuple->dst.u.gre.key;
1631 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
1633 + DEBUGP("%p: NATing GRE PPTP\n", conntrack);
1635 + range_size = 0xffff;
1638 + min = ntohl(range->min.gre.key);
1639 + range_size = ntohl(range->max.gre.key) - min + 1;
1642 + DEBUGP("min = %u, range_size = %u\n", min, range_size);
1644 + for (i = 0; i < range_size; i++, key++) {
1645 + *keyptr = htonl(min + key % range_size);
1646 + if (!ip_nat_used_tuple(tuple, conntrack))
1650 + DEBUGP("%p: no NAT mapping\n", conntrack);
1655 +/* manipulate a GRE packet according to maniptype */
1657 +gre_manip_pkt(struct iphdr *iph, size_t len,
1658 + const struct ip_conntrack_manip *manip,
1659 + enum ip_nat_manip_type maniptype)
1661 + struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
1662 + struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
1664 + /* we only have destination manip of a packet, since 'source key'
1665 + * is not present in the packet itself */
1666 + if (maniptype == IP_NAT_MANIP_DST) {
1667 + /* key manipulation is always dest */
1668 + switch (greh->version) {
1671 + DEBUGP("can't nat GRE w/o key\n");
1675 + /* FIXME: Never tested this code... */
1676 + *(gre_csum(greh)) =
1677 + ip_nat_cheat_check(~*(gre_key(greh)),
1679 + *(gre_csum(greh)));
1681 + *(gre_key(greh)) = manip->u.gre.key;
1683 + case GRE_VERSION_PPTP:
1684 + DEBUGP("call_id -> 0x%04x\n",
1685 + ntohl(manip->u.gre.key));
1686 + pgreh->call_id = htons(ntohl(manip->u.gre.key));
1689 + DEBUGP("can't nat unknown GRE version\n");
1695 +/* print out a nat tuple */
1696 +static unsigned int
1697 +gre_print(char *buffer,
1698 + const struct ip_conntrack_tuple *match,
1699 + const struct ip_conntrack_tuple *mask)
1701 + unsigned int len = 0;
1703 + if (mask->src.u.gre.key)
1704 + len += sprintf(buffer + len, "srckey=0x%x ",
1705 + ntohl(match->src.u.gre.key));
1707 + if (mask->dst.u.gre.key)
1708 + len += sprintf(buffer + len, "dstkey=0x%x ",
1709 + ntohl(match->src.u.gre.key));
1714 +/* print a range of keys */
1715 +static unsigned int
1716 +gre_print_range(char *buffer, const struct ip_nat_range *range)
1718 + if (range->min.gre.key != 0
1719 + || range->max.gre.key != 0xFFFF) {
1720 + if (range->min.gre.key == range->max.gre.key)
1721 + return sprintf(buffer, "key 0x%x ",
1722 + ntohl(range->min.gre.key));
1724 + return sprintf(buffer, "keys 0x%u-0x%u ",
1725 + ntohl(range->min.gre.key),
1726 + ntohl(range->max.gre.key));
1731 +/* nat helper struct */
1732 +static struct ip_nat_protocol gre =
1733 + { { NULL, NULL }, "GRE", IPPROTO_GRE,
1741 +static int __init init(void)
1743 + if (ip_nat_protocol_register(&gre))
1749 +static void __exit fini(void)
1751 + ip_nat_protocol_unregister(&gre);
1756 Index: linux-2.4.35.4/net/ipv4/netfilter/Makefile
1757 ===================================================================
1758 --- linux-2.4.35.4.orig/net/ipv4/netfilter/Makefile 2007-12-15 05:20:06.036184227 +0100
1759 +++ linux-2.4.35.4/net/ipv4/netfilter/Makefile 2007-12-15 05:20:06.408205428 +0100
1761 ifdef CONFIG_IP_NF_AMANDA
1762 export-objs += ip_conntrack_amanda.o
1765 obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
1766 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
1767 ifdef CONFIG_IP_NF_FTP
1768 export-objs += ip_conntrack_ftp.o
1771 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
1772 ifdef CONFIG_IP_NF_IRC
1773 export-objs += ip_conntrack_irc.o
1775 +obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
1776 +ifdef CONFIG_IP_NF_CT_PROTO_GRE
1777 + export-objs += ip_conntrack_proto_gre.o
1779 +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
1780 +ifdef CONFIG_IP_NF_NAT_PPTP
1781 + export-objs += ip_conntrack_pptp.o
1786 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
1787 obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
1788 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
1789 obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
1790 +obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
1791 +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
1794 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
1795 Index: linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_pptp.c
1796 ===================================================================
1797 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1798 +++ linux-2.4.35.4/net/ipv4/netfilter/ip_conntrack_pptp.c 2007-12-15 05:20:06.408205428 +0100
1801 + * ip_conntrack_pptp.c - Version 1.9
1803 + * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
1804 + * PPTP is a a protocol for creating virtual private networks.
1805 + * It is a specification defined by Microsoft and some vendors
1806 + * working with Microsoft. PPTP is built on top of a modified
1807 + * version of the Internet Generic Routing Encapsulation Protocol.
1808 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of
1809 + * PPTP can be found in RFC 2637
1811 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1813 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1816 + * - We blindly assume that control connections are always
1817 + * established in PNS->PAC direction. This is a violation
1820 + * TODO: - finish support for multiple calls within one session
1821 + * (needs expect reservations in newnat)
1822 + * - testing of incoming PPTP calls
1825 + * 2002-02-05 - Version 1.3
1826 + * - Call ip_conntrack_unexpect_related() from
1827 + * pptp_timeout_related() to destroy expectations in case
1828 + * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
1829 + * (Philip Craig <philipc@snapgear.com>)
1830 + * - Add Version information at module loadtime
1831 + * 2002-02-10 - Version 1.6
1832 + * - move to C99 style initializers
1833 + * - remove second expectation if first arrives
1837 +#include <linux/config.h>
1838 +#include <linux/module.h>
1839 +#include <linux/netfilter.h>
1840 +#include <linux/ip.h>
1841 +#include <net/checksum.h>
1842 +#include <net/tcp.h>
1844 +#include <linux/netfilter_ipv4/lockhelp.h>
1845 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1846 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1847 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1849 +#define IP_CT_PPTP_VERSION "1.9"
1851 +MODULE_LICENSE("GPL");
1852 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1853 +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
1855 +DECLARE_LOCK(ip_pptp_lock);
1858 +#include "ip_conntrack_pptp_priv.h"
1859 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1860 + ": " format, ## args)
1862 +#define DEBUGP(format, args...)
1866 +#define MINS * 60 SECS
1867 +#define HOURS * 60 MINS
1868 +#define DAYS * 24 HOURS
1870 +#define PPTP_GRE_TIMEOUT (10 MINS)
1871 +#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS)
1873 +static int pptp_expectfn(struct ip_conntrack *ct)
1875 + struct ip_conntrack *master;
1876 + struct ip_conntrack_expect *exp;
1878 + DEBUGP("increasing timeouts\n");
1879 + /* increase timeout of GRE data channel conntrack entry */
1880 + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
1881 + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
1883 + master = master_ct(ct);
1885 + DEBUGP(" no master!!!\n");
1891 + DEBUGP("no expectation!!\n");
1895 + DEBUGP("completing tuples with ct info\n");
1896 + /* we can do this, since we're unconfirmed */
1897 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1898 + htonl(master->help.ct_pptp_info.pac_call_id)) {
1899 + /* assume PNS->PAC */
1900 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1901 + htonl(master->help.ct_pptp_info.pns_call_id);
1902 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1903 + htonl(master->help.ct_pptp_info.pns_call_id);
1905 + /* assume PAC->PNS */
1906 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1907 + htonl(master->help.ct_pptp_info.pac_call_id);
1908 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1909 + htonl(master->help.ct_pptp_info.pac_call_id);
1912 + /* delete other expectation */
1913 + if (exp->expected_list.next != &exp->expected_list) {
1914 + struct ip_conntrack_expect *other_exp;
1915 + struct list_head *cur_item, *next;
1917 + for (cur_item = master->sibling_list.next;
1918 + cur_item != &master->sibling_list; cur_item = next) {
1919 + next = cur_item->next;
1920 + other_exp = list_entry(cur_item,
1921 + struct ip_conntrack_expect,
1923 + /* remove only if occurred at same sequence number */
1924 + if (other_exp != exp && other_exp->seq == exp->seq) {
1925 + DEBUGP("unexpecting other direction\n");
1926 + ip_ct_gre_keymap_destroy(other_exp);
1927 + ip_conntrack_unexpect_related(other_exp);
1935 +/* timeout GRE data connections */
1936 +static int pptp_timeout_related(struct ip_conntrack *ct)
1938 + struct list_head *cur_item, *next;
1939 + struct ip_conntrack_expect *exp;
1940 + enum ip_conntrack_info ctinfo;
1941 + struct iphdr *iph;
1943 + /* FIXME: do we have to lock something ? */
1944 + for (cur_item = ct->sibling_list.next;
1945 + cur_item != &ct->sibling_list; cur_item = next) {
1946 + next = cur_item->next;
1947 + exp = list_entry(cur_item, struct ip_conntrack_expect,
1950 + ip_ct_gre_keymap_destroy(exp);
1951 + if (!exp->sibling) {
1952 + ip_conntrack_unexpect_related(exp);
1956 + DEBUGP("setting timeout of conntrack %p to 0\n",
1958 + exp->sibling->proto.gre.timeout = 0;
1959 + exp->sibling->proto.gre.stream_timeout = 0;
1960 + ip_ct_refresh_acct(exp->sibling, ctinfo, iph, 0);
1966 +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
1968 +exp_gre(struct ip_conntrack *master,
1971 + u_int16_t peer_callid)
1973 + struct ip_conntrack_expect exp;
1974 + struct ip_conntrack_tuple inv_tuple;
1976 + memset(&exp, 0, sizeof(exp));
1977 + /* tuple in original direction, PNS->PAC */
1978 + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1979 + exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
1980 + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
1981 + exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
1982 + exp.tuple.dst.protonum = IPPROTO_GRE;
1984 + exp.mask.src.ip = 0xffffffff;
1985 + exp.mask.src.u.all = 0;
1986 + exp.mask.dst.u.all = 0;
1987 + exp.mask.dst.u.gre.key = 0xffffffff;
1988 + exp.mask.dst.ip = 0xffffffff;
1989 + exp.mask.dst.protonum = 0xffff;
1992 + exp.expectfn = pptp_expectfn;
1994 + exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
1995 + exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
1997 + DEBUGP("calling expect_related ");
1998 + DUMP_TUPLE_RAW(&exp.tuple);
2000 + /* Add GRE keymap entries */
2001 + if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
2004 + invert_tuplepr(&inv_tuple, &exp.tuple);
2005 + if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
2006 + ip_ct_gre_keymap_destroy(&exp);
2010 + if (ip_conntrack_expect_related(master, &exp) != 0) {
2011 + ip_ct_gre_keymap_destroy(&exp);
2012 + DEBUGP("cannot expect_related()\n");
2016 + /* tuple in reply direction, PAC->PNS */
2017 + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
2018 + exp.tuple.src.u.gre.key = htonl(ntohs(callid));
2019 + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
2020 + exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
2022 + DEBUGP("calling expect_related ");
2023 + DUMP_TUPLE_RAW(&exp.tuple);
2025 + /* Add GRE keymap entries */
2026 + ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
2027 + invert_tuplepr(&inv_tuple, &exp.tuple);
2028 + ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
2029 + /* FIXME: cannot handle error correctly, since we need to free
2030 + * the above keymap :( */
2032 + if (ip_conntrack_expect_related(master, &exp) != 0) {
2033 + /* free the second pair of keypmaps */
2034 + ip_ct_gre_keymap_destroy(&exp);
2035 + DEBUGP("cannot expect_related():\n");
2043 +pptp_inbound_pkt(struct tcphdr *tcph,
2044 + struct pptp_pkt_hdr *pptph,
2046 + struct ip_conntrack *ct,
2047 + enum ip_conntrack_info ctinfo)
2049 + struct PptpControlHeader *ctlh;
2050 + union pptp_ctrl_union pptpReq;
2052 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2053 + u_int16_t msg, *cid, *pcid;
2056 + ctlh = (struct PptpControlHeader *)
2057 + ((char *) pptph + sizeof(struct pptp_pkt_hdr));
2058 + pptpReq.rawreq = (void *)
2059 + ((char *) ctlh + sizeof(struct PptpControlHeader));
2061 + msg = ntohs(ctlh->messageType);
2062 + DEBUGP("inbound control message %s\n", strMName[msg]);
2065 + case PPTP_START_SESSION_REPLY:
2066 + /* server confirms new control session */
2067 + if (info->sstate < PPTP_SESSION_REQUESTED) {
2068 + DEBUGP("%s without START_SESS_REQUEST\n",
2072 + if (pptpReq.srep->resultCode == PPTP_START_OK)
2073 + info->sstate = PPTP_SESSION_CONFIRMED;
2075 + info->sstate = PPTP_SESSION_ERROR;
2078 + case PPTP_STOP_SESSION_REPLY:
2079 + /* server confirms end of control session */
2080 + if (info->sstate > PPTP_SESSION_STOPREQ) {
2081 + DEBUGP("%s without STOP_SESS_REQUEST\n",
2085 + if (pptpReq.strep->resultCode == PPTP_STOP_OK)
2086 + info->sstate = PPTP_SESSION_NONE;
2088 + info->sstate = PPTP_SESSION_ERROR;
2091 + case PPTP_OUT_CALL_REPLY:
2092 + /* server accepted call, we now expect GRE frames */
2093 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2094 + DEBUGP("%s but no session\n", strMName[msg]);
2097 + if (info->cstate != PPTP_CALL_OUT_REQ &&
2098 + info->cstate != PPTP_CALL_OUT_CONF) {
2099 + DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
2102 + if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
2103 + info->cstate = PPTP_CALL_NONE;
2107 + cid = &pptpReq.ocack->callID;
2108 + pcid = &pptpReq.ocack->peersCallID;
2110 + info->pac_call_id = ntohs(*cid);
2112 + if (htons(info->pns_call_id) != *pcid) {
2113 + DEBUGP("%s for unknown callid %u\n",
2114 + strMName[msg], ntohs(*pcid));
2118 + DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
2119 + ntohs(*cid), ntohs(*pcid));
2121 + info->cstate = PPTP_CALL_OUT_CONF;
2123 + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2124 + if (exp_gre(ct, seq, *cid, *pcid) != 0)
2125 + printk("ip_conntrack_pptp: error during exp_gre\n");
2128 + case PPTP_IN_CALL_REQUEST:
2129 + /* server tells us about incoming call request */
2130 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2131 + DEBUGP("%s but no session\n", strMName[msg]);
2134 + pcid = &pptpReq.icack->peersCallID;
2135 + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2136 + info->cstate = PPTP_CALL_IN_REQ;
2137 + info->pac_call_id= ntohs(*pcid);
2140 + case PPTP_IN_CALL_CONNECT:
2141 + /* server tells us about incoming call established */
2142 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2143 + DEBUGP("%s but no session\n", strMName[msg]);
2146 + if (info->sstate != PPTP_CALL_IN_REP
2147 + && info->sstate != PPTP_CALL_IN_CONF) {
2148 + DEBUGP("%s but never sent IN_CALL_REPLY\n",
2153 + pcid = &pptpReq.iccon->peersCallID;
2154 + cid = &info->pac_call_id;
2156 + if (info->pns_call_id != ntohs(*pcid)) {
2157 + DEBUGP("%s for unknown CallID %u\n",
2158 + strMName[msg], ntohs(*cid));
2162 + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
2163 + info->cstate = PPTP_CALL_IN_CONF;
2165 + /* we expect a GRE connection from PAC to PNS */
2166 + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
2167 + if (exp_gre(ct, seq, *cid, *pcid) != 0)
2168 + printk("ip_conntrack_pptp: error during exp_gre\n");
2172 + case PPTP_CALL_DISCONNECT_NOTIFY:
2173 + /* server confirms disconnect */
2174 + cid = &pptpReq.disc->callID;
2175 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2176 + info->cstate = PPTP_CALL_NONE;
2178 + /* untrack this call id, unexpect GRE packets */
2179 + pptp_timeout_related(ct);
2182 + case PPTP_WAN_ERROR_NOTIFY:
2185 + case PPTP_ECHO_REQUEST:
2186 + case PPTP_ECHO_REPLY:
2187 + /* I don't have to explain these ;) */
2190 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
2191 + ? strMName[msg]:strMName[0], msg);
2200 +pptp_outbound_pkt(struct tcphdr *tcph,
2201 + struct pptp_pkt_hdr *pptph,
2203 + struct ip_conntrack *ct,
2204 + enum ip_conntrack_info ctinfo)
2206 + struct PptpControlHeader *ctlh;
2207 + union pptp_ctrl_union pptpReq;
2208 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2209 + u_int16_t msg, *cid, *pcid;
2211 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
2212 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
2214 + msg = ntohs(ctlh->messageType);
2215 + DEBUGP("outbound control message %s\n", strMName[msg]);
2218 + case PPTP_START_SESSION_REQUEST:
2219 + /* client requests for new control session */
2220 + if (info->sstate != PPTP_SESSION_NONE) {
2221 + DEBUGP("%s but we already have one",
2224 + info->sstate = PPTP_SESSION_REQUESTED;
2226 + case PPTP_STOP_SESSION_REQUEST:
2227 + /* client requests end of control session */
2228 + info->sstate = PPTP_SESSION_STOPREQ;
2231 + case PPTP_OUT_CALL_REQUEST:
2232 + /* client initiating connection to server */
2233 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2234 + DEBUGP("%s but no session\n",
2238 + info->cstate = PPTP_CALL_OUT_REQ;
2239 + /* track PNS call id */
2240 + cid = &pptpReq.ocreq->callID;
2241 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
2242 + info->pns_call_id = ntohs(*cid);
2244 + case PPTP_IN_CALL_REPLY:
2245 + /* client answers incoming call */
2246 + if (info->cstate != PPTP_CALL_IN_REQ
2247 + && info->cstate != PPTP_CALL_IN_REP) {
2248 + DEBUGP("%s without incall_req\n",
2252 + if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
2253 + info->cstate = PPTP_CALL_NONE;
2256 + pcid = &pptpReq.icack->peersCallID;
2257 + if (info->pac_call_id != ntohs(*pcid)) {
2258 + DEBUGP("%s for unknown call %u\n",
2259 + strMName[msg], ntohs(*pcid));
2262 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
2263 + /* part two of the three-way handshake */
2264 + info->cstate = PPTP_CALL_IN_REP;
2265 + info->pns_call_id = ntohs(pptpReq.icack->callID);
2268 + case PPTP_CALL_CLEAR_REQUEST:
2269 + /* client requests hangup of call */
2270 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
2271 + DEBUGP("CLEAR_CALL but no session\n");
2274 + /* FUTURE: iterate over all calls and check if
2275 + * call ID is valid. We don't do this without newnat,
2276 + * because we only know about last call */
2277 + info->cstate = PPTP_CALL_CLEAR_REQ;
2279 + case PPTP_SET_LINK_INFO:
2281 + case PPTP_ECHO_REQUEST:
2282 + case PPTP_ECHO_REPLY:
2283 + /* I don't have to explain these ;) */
2286 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
2287 + strMName[msg]:strMName[0], msg);
2288 + /* unknown: no need to create GRE masq table entry */
2296 +/* track caller id inside control connection, call expect_related */
2298 +conntrack_pptp_help(const struct iphdr *iph, size_t len,
2299 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
2302 + struct pptp_pkt_hdr *pptph;
2304 + struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
2305 + u_int32_t tcplen = len - iph->ihl * 4;
2306 + u_int32_t datalen = tcplen - tcph->doff * 4;
2308 + int dir = CTINFO2DIR(ctinfo);
2309 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
2311 + int oldsstate, oldcstate;
2314 + /* don't do any tracking before tcp handshake complete */
2315 + if (ctinfo != IP_CT_ESTABLISHED
2316 + && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
2317 + DEBUGP("ctinfo = %u, skipping\n", ctinfo);
2321 + /* not a complete TCP header? */
2322 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
2323 + DEBUGP("tcplen = %u\n", tcplen);
2327 + /* checksum invalid? */
2328 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
2329 + csum_partial((char *) tcph, tcplen, 0))) {
2330 + printk(KERN_NOTICE __FILE__ ": bad csum\n");
2331 + /* W2K PPTP server sends TCP packets with wrong checksum :(( */
2332 + //return NF_ACCEPT;
2335 + if (tcph->fin || tcph->rst) {
2336 + DEBUGP("RST/FIN received, timeouting GRE\n");
2337 + /* can't do this after real newnat */
2338 + info->cstate = PPTP_CALL_NONE;
2340 + /* untrack this call id, unexpect GRE packets */
2341 + pptp_timeout_related(ct);
2345 + pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
2346 + datalimit = (void *) pptph + datalen;
2348 + /* not a full pptp packet header? */
2349 + if ((void *) pptph+sizeof(*pptph) >= datalimit) {
2350 + DEBUGP("no full PPTP header, can't track\n");
2354 + /* if it's not a control message we can't do anything with it */
2355 + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
2356 + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
2357 + DEBUGP("not a control packet\n");
2361 + oldsstate = info->sstate;
2362 + oldcstate = info->cstate;
2364 + LOCK_BH(&ip_pptp_lock);
2366 + /* FIXME: We just blindly assume that the control connection is always
2367 + * established from PNS->PAC. However, RFC makes no guarantee */
2368 + if (dir == IP_CT_DIR_ORIGINAL)
2369 + /* client -> server (PNS -> PAC) */
2370 + ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2372 + /* server -> client (PAC -> PNS) */
2373 + ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
2374 + DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
2375 + oldsstate, info->sstate, oldcstate, info->cstate);
2376 + UNLOCK_BH(&ip_pptp_lock);
2381 +/* control protocol helper */
2382 +static struct ip_conntrack_helper pptp = {
2383 + .list = { NULL, NULL },
2385 + .flags = IP_CT_HELPER_F_REUSE_EXPECT,
2386 + .me = THIS_MODULE,
2387 + .max_expected = 2,
2389 + .tuple = { .src = { .ip = 0,
2390 + .u = { .tcp = { .port =
2391 + __constant_htons(PPTP_CONTROL_PORT) } }
2394 + .u = { .all = 0 },
2395 + .protonum = IPPROTO_TCP
2398 + .mask = { .src = { .ip = 0,
2399 + .u = { .tcp = { .port = 0xffff } }
2402 + .u = { .all = 0 },
2403 + .protonum = 0xffff
2406 + .help = conntrack_pptp_help
2409 +/* ip_conntrack_pptp initialization */
2410 +static int __init init(void)
2414 + DEBUGP(__FILE__ ": registering helper\n");
2415 + if ((retcode = ip_conntrack_helper_register(&pptp))) {
2416 + printk(KERN_ERR "Unable to register conntrack application "
2417 + "helper for pptp: %d\n", retcode);
2421 + printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
2425 +static void __exit fini(void)
2427 + ip_conntrack_helper_unregister(&pptp);
2428 + printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
2434 +EXPORT_SYMBOL(ip_pptp_lock);