1 diff -Nur linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack.h
2 --- linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack.h 2003-12-18 03:59:40.000000000 +0100
3 +++ linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack.h 2003-12-19 14:14:23.000000000 +0100
6 #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
7 #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
8 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
10 /* per conntrack: protocol private data */
11 union ip_conntrack_proto {
12 /* insert conntrack proto private data here */
13 + struct ip_ct_gre gre;
15 struct ip_ct_icmp icmp;
18 union ip_conntrack_expect_proto {
19 /* insert expect proto private data here */
20 + struct ip_ct_gre_expect gre;
23 /* Add protocol helper include file here */
24 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
25 #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
26 #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
27 #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
29 /* per expectation: application helper private data */
30 union ip_conntrack_expect_help {
31 /* insert conntrack helper private data (expect) here */
32 + struct ip_ct_pptp_expect exp_pptp_info;
33 struct ip_ct_amanda_expect exp_amanda_info;
34 struct ip_ct_ftp_expect exp_ftp_info;
35 struct ip_ct_irc_expect exp_irc_info;
37 /* per conntrack: application helper private data */
38 union ip_conntrack_help {
39 /* insert conntrack helper private data (master) here */
40 + struct ip_ct_pptp_master ct_pptp_info;
41 struct ip_ct_ftp_master ct_ftp_info;
42 struct ip_ct_irc_master ct_irc_info;
45 #ifdef CONFIG_IP_NF_NAT_NEEDED
46 #include <linux/netfilter_ipv4/ip_nat.h>
47 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
49 /* per conntrack: nat application helper private data */
50 union ip_conntrack_nat_help {
51 /* insert nat helper private data here */
52 + struct ip_nat_pptp nat_pptp_info;
56 diff -Nur linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
57 --- linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1970-01-01 01:00:00.000000000 +0100
58 +++ linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2003-11-17 09:09:34.000000000 +0100
60 +/* PPTP constants and structs */
61 +#ifndef _CONNTRACK_PPTP_H
62 +#define _CONNTRACK_PPTP_H
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 */
73 +/* state of the call inside the control session */
74 +enum pptp_ctrlcall_state {
82 + PPTP_CALL_CLEAR_REQ,
86 +/* conntrack private data */
87 +struct ip_ct_pptp_master {
88 + enum pptp_ctrlsess_state sstate; /* session state */
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 */
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 */
107 +#include <linux/netfilter_ipv4/lockhelp.h>
108 +DECLARE_LOCK_EXTERN(ip_pptp_lock);
110 +#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
112 +union pptp_ctrl_union {
114 + struct PptpStartSessionRequest *sreq;
115 + struct PptpStartSessionReply *srep;
116 + struct PptpStopSessionReqest *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;
131 +#define PPTP_CONTROL_PORT 1723
133 +#define PPTP_PACKET_CONTROL 1
134 +#define PPTP_PACKET_MGMT 2
136 +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d
138 +struct pptp_pkt_hdr {
139 + __u16 packetLength;
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
161 +#define PPTP_MSG_MAX 15
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
172 +struct PptpControlHeader {
177 +/* FramingCapability Bitmap Values */
178 +#define PPTP_FRAME_CAP_ASYNC 0x1
179 +#define PPTP_FRAME_CAP_SYNC 0x2
181 +/* BearerCapability Bitmap Values */
182 +#define PPTP_BEARER_CAP_ANALOG 0x1
183 +#define PPTP_BEARER_CAP_DIGITAL 0x2
185 +struct PptpStartSessionRequest {
186 + __u16 protocolVersion;
189 + __u32 framingCapability;
190 + __u32 bearerCapability;
192 + __u16 firmwareRevision;
194 + __u8 vendorString[64];
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
204 +struct PptpStartSessionReply {
205 + __u16 protocolVersion;
207 + __u8 generalErrorCode;
208 + __u32 framingCapability;
209 + __u32 bearerCapability;
211 + __u16 firmwareRevision;
213 + __u8 vendorString[64];
216 +/* PptpStopReasons */
217 +#define PPTP_STOP_NONE 1
218 +#define PPTP_STOP_PROTOCOL 2
219 +#define PPTP_STOP_LOCAL_SHUTDOWN 3
221 +struct PptpStopSessionRequest {
225 +/* PptpStopSessionResultCode */
226 +#define PPTP_STOP_OK 1
227 +#define PPTP_STOP_GENERAL_ERROR 2
229 +struct PptpStopSessionReply {
231 + __u8 generalErrorCode;
234 +struct PptpEchoRequest {
238 +/* PptpEchoReplyResultCode */
239 +#define PPTP_ECHO_OK 1
240 +#define PPTP_ECHO_GENERAL_ERROR 2
242 +struct PptpEchoReply {
245 + __u8 generalErrorCode;
249 +/* PptpFramingType */
250 +#define PPTP_ASYNC_FRAMING 1
251 +#define PPTP_SYNC_FRAMING 2
252 +#define PPTP_DONT_CARE_FRAMING 3
254 +/* PptpCallBearerType */
255 +#define PPTP_ANALOG_TYPE 1
256 +#define PPTP_DIGITAL_TYPE 2
257 +#define PPTP_DONT_CARE_BEARER_TYPE 3
259 +struct PptpOutCallRequest {
261 + __u16 callSerialNumber;
266 + __u16 packetWindow;
267 + __u16 packetProcDelay;
269 + __u16 phoneNumberLength;
271 + __u8 phoneNumber[64];
272 + __u8 subAddress[64];
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
284 +struct PptpOutCallReply {
288 + __u8 generalErrorCode;
290 + __u32 connectSpeed;
291 + __u16 packetWindow;
292 + __u16 packetProcDelay;
293 + __u32 physChannelID;
296 +struct PptpInCallRequest {
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];
308 +/* PptpInCallResultCode */
309 +#define PPTP_INCALL_ACCEPT 1
310 +#define PPTP_INCALL_GENERAL_ERROR 2
311 +#define PPTP_INCALL_DONT_ACCEPT 3
313 +struct PptpInCallReply {
317 + __u8 generalErrorCode;
318 + __u16 packetWindow;
319 + __u16 packetProcDelay;
323 +struct PptpInCallConnected {
326 + __u32 connectSpeed;
327 + __u16 packetWindow;
328 + __u16 packetProcDelay;
329 + __u32 callFramingType;
332 +struct PptpClearCallRequest {
337 +struct PptpCallDisconnectNotify {
340 + __u8 generalErrorCode;
343 + __u8 callStatistics[128];
346 +struct PptpWanErrorNotify {
350 + __u32 framingErrors;
351 + __u32 hardwareOverRuns;
352 + __u32 bufferOverRuns;
353 + __u32 timeoutErrors;
354 + __u32 alignmentErrors;
357 +struct PptpSetLinkInfo {
365 +struct pptp_priv_data {
371 +#endif /* __KERNEL__ */
372 +#endif /* _CONNTRACK_PPTP_H */
373 diff -Nur linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
374 --- linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1970-01-01 01:00:00.000000000 +0100
375 +++ linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2003-11-17 09:09:34.000000000 +0100
377 +#ifndef _CONNTRACK_PROTO_GRE_H
378 +#define _CONNTRACK_PROTO_GRE_H
379 +#include <asm/byteorder.h>
381 +/* GRE PROTOCOL HEADER */
383 +/* GRE Version field */
384 +#define GRE_VERSION_1701 0x0
385 +#define GRE_VERSION_PPTP 0x1
387 +/* GRE Protocol field */
388 +#define GRE_PROTOCOL_PPTP 0x880B
391 +#define GRE_FLAG_C 0x80
392 +#define GRE_FLAG_R 0x40
393 +#define GRE_FLAG_K 0x20
394 +#define GRE_FLAG_S 0x10
395 +#define GRE_FLAG_A 0x80
397 +#define GRE_IS_C(f) ((f)&GRE_FLAG_C)
398 +#define GRE_IS_R(f) ((f)&GRE_FLAG_R)
399 +#define GRE_IS_K(f) ((f)&GRE_FLAG_K)
400 +#define GRE_IS_S(f) ((f)&GRE_FLAG_S)
401 +#define GRE_IS_A(f) ((f)&GRE_FLAG_A)
403 +/* GRE is a mess: Four different standards */
405 +#if defined(__LITTLE_ENDIAN_BITFIELD)
415 +#elif defined(__BIG_ENDIAN_BITFIELD)
426 +#error "Adjust your <asm/byteorder.h> defines"
431 +/* modified GRE header for PPTP */
432 +struct gre_hdr_pptp {
433 + __u8 flags; /* bitfield */
434 + __u8 version; /* should be GRE_VERSION_PPTP */
435 + __u16 protocol; /* should be GRE_PROTOCOL_PPTP */
436 + __u16 payload_len; /* size of ppp payload, not inc. gre header */
437 + __u16 call_id; /* peer's call_id for this session */
438 + __u32 seq; /* sequence number. Present if S==1 */
439 + __u32 ack; /* seq number of highest packet recieved by */
440 + /* sender in this session */
444 +/* this is part of ip_conntrack */
446 + unsigned int stream_timeout;
447 + unsigned int timeout;
450 +/* this is part of ip_conntrack_expect */
451 +struct ip_ct_gre_expect {
452 + struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
456 +struct ip_conntrack_expect;
458 +/* structure for original <-> reply keymap */
459 +struct ip_ct_gre_keymap {
460 + struct list_head list;
462 + struct ip_conntrack_tuple tuple;
466 +/* add new tuple->key_reply pair to keymap */
467 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
468 + struct ip_conntrack_tuple *t,
471 +/* change an existing keymap entry */
472 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
473 + struct ip_conntrack_tuple *t);
475 +/* delete keymap entries */
476 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
479 +/* get pointer to gre key, if present */
480 +static inline u_int32_t *gre_key(struct gre_hdr *greh)
484 + if (greh->csum || greh->routing)
485 + return (u_int32_t *) (greh+sizeof(*greh)+4);
486 + return (u_int32_t *) (greh+sizeof(*greh));
489 +/* get pointer ot gre csum, if present */
490 +static inline u_int16_t *gre_csum(struct gre_hdr *greh)
494 + return (u_int16_t *) (greh+sizeof(*greh));
497 +#endif /* __KERNEL__ */
499 +#endif /* _CONNTRACK_PROTO_GRE_H */
500 diff -Nur linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
501 --- linux-2.6.0.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-12-18 03:59:16.000000000 +0100
502 +++ linux-2.6.0/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-12-19 14:14:23.000000000 +0100
504 union ip_conntrack_manip_proto
506 /* Add other protocols here. */
521 /* The manipulable part of the tuple. */
525 /* Add other protocols here. */
536 + u_int16_t protocol;
546 #define DUMP_TUPLE(tp) \
547 -DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
548 +DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \
549 (tp), (tp)->dst.protonum, \
550 - NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
551 - NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
552 + NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \
553 + NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all))
555 +#define DUMP_TUPLE_RAW(x) \
556 + DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\
557 + (x), (x)->dst.protonum, \
558 + NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \
559 + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all))
561 #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
563 diff -Nur linux-2.6.0.org/include/linux/netfilter_ipv4/ip_nat_pptp.h linux-2.6.0/include/linux/netfilter_ipv4/ip_nat_pptp.h
564 --- linux-2.6.0.org/include/linux/netfilter_ipv4/ip_nat_pptp.h 1970-01-01 01:00:00.000000000 +0100
565 +++ linux-2.6.0/include/linux/netfilter_ipv4/ip_nat_pptp.h 2003-11-17 09:09:34.000000000 +0100
567 +/* PPTP constants and structs */
571 +/* conntrack private data */
572 +struct ip_nat_pptp {
573 + u_int16_t pns_call_id; /* NAT'ed PNS call id */
574 + u_int16_t pac_call_id; /* NAT'ed PAC call id */
577 +#endif /* _NAT_PPTP_H */
578 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/Makefile linux-2.6.0/net/ipv4/netfilter/Makefile
579 --- linux-2.6.0.org/net/ipv4/netfilter/Makefile 2003-12-18 03:58:28.000000000 +0100
580 +++ linux-2.6.0/net/ipv4/netfilter/Makefile 2003-12-19 14:16:02.000000000 +0100
582 # connection tracking
583 obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
585 +# connection tracking protocol helpers
586 +obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
588 +# NAT protocol helpers
589 +obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
591 # connection tracking helpers
592 +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
593 obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
594 obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
595 obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
596 obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
599 +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
600 obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
601 obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
602 obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
603 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.0/net/ipv4/netfilter/ip_conntrack_core.c
604 --- linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_core.c 2003-12-18 03:57:57.000000000 +0100
605 +++ linux-2.6.0/net/ipv4/netfilter/ip_conntrack_core.c 2003-12-19 14:14:23.000000000 +0100
607 inverse->dst.ip = orig->src.ip;
608 inverse->dst.protonum = orig->dst.protonum;
610 + inverse->src.u.all = inverse->dst.u.all = 0;
612 return protocol->invert_tuple(inverse, orig);
616 * so there is no need to use the tuple lock too */
618 DEBUGP("ip_conntrack_expect_related %p\n", related_to);
619 - DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
620 - DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
621 + DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
622 + DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask);
624 old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
625 struct ip_conntrack_expect *, &expect->tuple,
626 @@ -1051,15 +1053,14 @@
628 MUST_BE_READ_LOCKED(&ip_conntrack_lock);
629 WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
631 DEBUGP("change_expect:\n");
632 - DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
633 - DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
634 - DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
635 + DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
636 + DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask);
637 + DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple);
638 if (expect->ct_tuple.dst.protonum == 0) {
639 /* Never seen before */
640 DEBUGP("change expect: never seen before\n");
641 - if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
642 + if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
643 && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
644 struct ip_conntrack_expect *, newtuple, &expect->mask)) {
645 /* Force NAT to find an unused tuple */
646 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_pptp.c linux-2.6.0/net/ipv4/netfilter/ip_conntrack_pptp.c
647 --- linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100
648 +++ linux-2.6.0/net/ipv4/netfilter/ip_conntrack_pptp.c 2003-11-17 09:09:34.000000000 +0100
651 + * ip_conntrack_pptp.c - Version 1.9
653 + * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
654 + * PPTP is a a protocol for creating virtual private networks.
655 + * It is a specification defined by Microsoft and some vendors
656 + * working with Microsoft. PPTP is built on top of a modified
657 + * version of the Internet Generic Routing Encapsulation Protocol.
658 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of
659 + * PPTP can be found in RFC 2637
661 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
663 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
666 + * - We blindly assume that control connections are always
667 + * established in PNS->PAC direction. This is a violation
670 + * TODO: - finish support for multiple calls within one session
671 + * (needs expect reservations in newnat)
672 + * - testing of incoming PPTP calls
675 + * 2002-02-05 - Version 1.3
676 + * - Call ip_conntrack_unexpect_related() from
677 + * pptp_timeout_related() to destroy expectations in case
678 + * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
679 + * (Philip Craig <philipc@snapgear.com>)
680 + * - Add Version information at module loadtime
681 + * 2002-02-10 - Version 1.6
682 + * - move to C99 style initializers
683 + * - remove second expectation if first arrives
687 +#include <linux/config.h>
688 +#include <linux/module.h>
689 +#include <linux/netfilter.h>
690 +#include <linux/ip.h>
691 +#include <net/checksum.h>
692 +#include <net/tcp.h>
694 +#include <linux/netfilter_ipv4/lockhelp.h>
695 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
696 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
697 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
699 +#define IP_CT_PPTP_VERSION "1.9"
701 +MODULE_LICENSE("GPL");
702 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
703 +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
705 +DECLARE_LOCK(ip_pptp_lock);
708 +#include "ip_conntrack_pptp_priv.h"
709 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
710 + ": " format, ## args)
712 +#define DEBUGP(format, args...)
716 +#define MINS * 60 SECS
717 +#define HOURS * 60 MINS
718 +#define DAYS * 24 HOURS
720 +#define PPTP_GRE_TIMEOUT (10 MINS)
721 +#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS)
723 +static int pptp_expectfn(struct ip_conntrack *ct)
725 + struct ip_conntrack *master;
726 + struct ip_conntrack_expect *exp;
728 + DEBUGP("increasing timeouts\n");
729 + /* increase timeout of GRE data channel conntrack entry */
730 + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
731 + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
733 + master = master_ct(ct);
735 + DEBUGP(" no master!!!\n");
741 + DEBUGP("no expectation!!\n");
745 + DEBUGP("completing tuples with ct info\n");
746 + /* we can do this, since we're unconfirmed */
747 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
748 + htonl(master->help.ct_pptp_info.pac_call_id)) {
749 + /* assume PNS->PAC */
750 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
751 + htonl(master->help.ct_pptp_info.pns_call_id);
752 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
753 + htonl(master->help.ct_pptp_info.pns_call_id);
755 + /* assume PAC->PNS */
756 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
757 + htonl(master->help.ct_pptp_info.pac_call_id);
758 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
759 + htonl(master->help.ct_pptp_info.pac_call_id);
762 + /* delete other expectation */
763 + if (exp->expected_list.next != &exp->expected_list) {
764 + struct ip_conntrack_expect *other_exp;
765 + struct list_head *cur_item, *next;
767 + for (cur_item = master->sibling_list.next;
768 + cur_item != &master->sibling_list; cur_item = next) {
769 + next = cur_item->next;
770 + other_exp = list_entry(cur_item,
771 + struct ip_conntrack_expect,
773 + /* remove only if occurred at same sequence number */
774 + if (other_exp != exp && other_exp->seq == exp->seq) {
775 + DEBUGP("unexpecting other direction\n");
776 + ip_ct_gre_keymap_destroy(other_exp);
777 + ip_conntrack_unexpect_related(other_exp);
785 +/* timeout GRE data connections */
786 +static int pptp_timeout_related(struct ip_conntrack *ct)
788 + struct list_head *cur_item, *next;
789 + struct ip_conntrack_expect *exp;
791 + /* FIXME: do we have to lock something ? */
792 + for (cur_item = ct->sibling_list.next;
793 + cur_item != &ct->sibling_list; cur_item = next) {
794 + next = cur_item->next;
795 + exp = list_entry(cur_item, struct ip_conntrack_expect,
798 + ip_ct_gre_keymap_destroy(exp);
799 + if (!exp->sibling) {
800 + ip_conntrack_unexpect_related(exp);
804 + DEBUGP("setting timeout of conntrack %p to 0\n",
806 + exp->sibling->proto.gre.timeout = 0;
807 + exp->sibling->proto.gre.stream_timeout = 0;
808 + ip_ct_refresh(exp->sibling, 0);
814 +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
816 +exp_gre(struct ip_conntrack *master,
819 + u_int16_t peer_callid)
821 + struct ip_conntrack_expect exp;
822 + struct ip_conntrack_tuple inv_tuple;
824 + memset(&exp, 0, sizeof(exp));
825 + /* tuple in original direction, PNS->PAC */
826 + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
827 + exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
828 + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
829 + exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
830 + exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP);
831 + exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP;
832 + exp.tuple.dst.protonum = IPPROTO_GRE;
834 + exp.mask.src.ip = 0xffffffff;
835 + exp.mask.src.u.all = 0;
836 + exp.mask.dst.u.all = 0;
837 + exp.mask.dst.u.gre.key = 0xffffffff;
838 + exp.mask.dst.u.gre.version = 0xff;
839 + exp.mask.dst.u.gre.protocol = 0xffff;
840 + exp.mask.dst.ip = 0xffffffff;
841 + exp.mask.dst.protonum = 0xffff;
844 + exp.expectfn = pptp_expectfn;
846 + exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
847 + exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
849 + DEBUGP("calling expect_related ");
850 + DUMP_TUPLE_RAW(&exp.tuple);
852 + /* Add GRE keymap entries */
853 + if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
856 + invert_tuplepr(&inv_tuple, &exp.tuple);
857 + if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
858 + ip_ct_gre_keymap_destroy(&exp);
862 + if (ip_conntrack_expect_related(master, &exp) != 0) {
863 + ip_ct_gre_keymap_destroy(&exp);
864 + DEBUGP("cannot expect_related()\n");
868 + /* tuple in reply direction, PAC->PNS */
869 + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
870 + exp.tuple.src.u.gre.key = htonl(ntohs(callid));
871 + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
872 + exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
874 + DEBUGP("calling expect_related ");
875 + DUMP_TUPLE_RAW(&exp.tuple);
877 + /* Add GRE keymap entries */
878 + ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
879 + invert_tuplepr(&inv_tuple, &exp.tuple);
880 + ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
881 + /* FIXME: cannot handle error correctly, since we need to free
882 + * the above keymap :( */
884 + if (ip_conntrack_expect_related(master, &exp) != 0) {
885 + /* free the second pair of keypmaps */
886 + ip_ct_gre_keymap_destroy(&exp);
887 + DEBUGP("cannot expect_related():\n");
895 +pptp_inbound_pkt(struct tcphdr *tcph,
896 + struct pptp_pkt_hdr *pptph,
898 + struct ip_conntrack *ct,
899 + enum ip_conntrack_info ctinfo)
901 + struct PptpControlHeader *ctlh;
902 + union pptp_ctrl_union pptpReq;
904 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
905 + u_int16_t msg, *cid, *pcid;
908 + ctlh = (struct PptpControlHeader *)
909 + ((char *) pptph + sizeof(struct pptp_pkt_hdr));
910 + pptpReq.rawreq = (void *)
911 + ((char *) ctlh + sizeof(struct PptpControlHeader));
913 + msg = ntohs(ctlh->messageType);
914 + DEBUGP("inbound control message %s\n", strMName[msg]);
917 + case PPTP_START_SESSION_REPLY:
918 + /* server confirms new control session */
919 + if (info->sstate < PPTP_SESSION_REQUESTED) {
920 + DEBUGP("%s without START_SESS_REQUEST\n",
924 + if (pptpReq.srep->resultCode == PPTP_START_OK)
925 + info->sstate = PPTP_SESSION_CONFIRMED;
927 + info->sstate = PPTP_SESSION_ERROR;
930 + case PPTP_STOP_SESSION_REPLY:
931 + /* server confirms end of control session */
932 + if (info->sstate > PPTP_SESSION_STOPREQ) {
933 + DEBUGP("%s without STOP_SESS_REQUEST\n",
937 + if (pptpReq.strep->resultCode == PPTP_STOP_OK)
938 + info->sstate = PPTP_SESSION_NONE;
940 + info->sstate = PPTP_SESSION_ERROR;
943 + case PPTP_OUT_CALL_REPLY:
944 + /* server accepted call, we now expect GRE frames */
945 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
946 + DEBUGP("%s but no session\n", strMName[msg]);
949 + if (info->cstate != PPTP_CALL_OUT_REQ &&
950 + info->cstate != PPTP_CALL_OUT_CONF) {
951 + DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
954 + if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
955 + info->cstate = PPTP_CALL_NONE;
959 + cid = &pptpReq.ocack->callID;
960 + pcid = &pptpReq.ocack->peersCallID;
962 + info->pac_call_id = ntohs(*cid);
964 + if (htons(info->pns_call_id) != *pcid) {
965 + DEBUGP("%s for unknown callid %u\n",
966 + strMName[msg], ntohs(*pcid));
970 + DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
971 + ntohs(*cid), ntohs(*pcid));
973 + info->cstate = PPTP_CALL_OUT_CONF;
975 + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
976 + if (exp_gre(ct, seq, *cid, *pcid) != 0)
977 + printk("ip_conntrack_pptp: error during exp_gre\n");
980 + case PPTP_IN_CALL_REQUEST:
981 + /* server tells us about incoming call request */
982 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
983 + DEBUGP("%s but no session\n", strMName[msg]);
986 + pcid = &pptpReq.icack->peersCallID;
987 + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
988 + info->cstate = PPTP_CALL_IN_REQ;
989 + info->pac_call_id= ntohs(*pcid);
992 + case PPTP_IN_CALL_CONNECT:
993 + /* server tells us about incoming call established */
994 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
995 + DEBUGP("%s but no session\n", strMName[msg]);
998 + if (info->sstate != PPTP_CALL_IN_REP
999 + && info->sstate != PPTP_CALL_IN_CONF) {
1000 + DEBUGP("%s but never sent IN_CALL_REPLY\n",
1005 + pcid = &pptpReq.iccon->peersCallID;
1006 + cid = &info->pac_call_id;
1008 + if (info->pns_call_id != ntohs(*pcid)) {
1009 + DEBUGP("%s for unknown CallID %u\n",
1010 + strMName[msg], ntohs(*cid));
1014 + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
1015 + info->cstate = PPTP_CALL_IN_CONF;
1017 + /* we expect a GRE connection from PAC to PNS */
1018 + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
1019 + if (exp_gre(ct, seq, *cid, *pcid) != 0)
1020 + printk("ip_conntrack_pptp: error during exp_gre\n");
1024 + case PPTP_CALL_DISCONNECT_NOTIFY:
1025 + /* server confirms disconnect */
1026 + cid = &pptpReq.disc->callID;
1027 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
1028 + info->cstate = PPTP_CALL_NONE;
1030 + /* untrack this call id, unexpect GRE packets */
1031 + pptp_timeout_related(ct);
1034 + case PPTP_WAN_ERROR_NOTIFY:
1037 + case PPTP_ECHO_REQUEST:
1038 + case PPTP_ECHO_REPLY:
1039 + /* I don't have to explain these ;) */
1042 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
1043 + ? strMName[msg]:strMName[0], msg);
1052 +pptp_outbound_pkt(struct tcphdr *tcph,
1053 + struct pptp_pkt_hdr *pptph,
1055 + struct ip_conntrack *ct,
1056 + enum ip_conntrack_info ctinfo)
1058 + struct PptpControlHeader *ctlh;
1059 + union pptp_ctrl_union pptpReq;
1060 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
1061 + u_int16_t msg, *cid, *pcid;
1063 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
1064 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
1066 + msg = ntohs(ctlh->messageType);
1067 + DEBUGP("outbound control message %s\n", strMName[msg]);
1070 + case PPTP_START_SESSION_REQUEST:
1071 + /* client requests for new control session */
1072 + if (info->sstate != PPTP_SESSION_NONE) {
1073 + DEBUGP("%s but we already have one",
1076 + info->sstate = PPTP_SESSION_REQUESTED;
1078 + case PPTP_STOP_SESSION_REQUEST:
1079 + /* client requests end of control session */
1080 + info->sstate = PPTP_SESSION_STOPREQ;
1083 + case PPTP_OUT_CALL_REQUEST:
1084 + /* client initiating connection to server */
1085 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
1086 + DEBUGP("%s but no session\n",
1090 + info->cstate = PPTP_CALL_OUT_REQ;
1091 + /* track PNS call id */
1092 + cid = &pptpReq.ocreq->callID;
1093 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
1094 + info->pns_call_id = ntohs(*cid);
1096 + case PPTP_IN_CALL_REPLY:
1097 + /* client answers incoming call */
1098 + if (info->cstate != PPTP_CALL_IN_REQ
1099 + && info->cstate != PPTP_CALL_IN_REP) {
1100 + DEBUGP("%s without incall_req\n",
1104 + if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
1105 + info->cstate = PPTP_CALL_NONE;
1108 + pcid = &pptpReq.icack->peersCallID;
1109 + if (info->pac_call_id != ntohs(*pcid)) {
1110 + DEBUGP("%s for unknown call %u\n",
1111 + strMName[msg], ntohs(*pcid));
1114 + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
1115 + /* part two of the three-way handshake */
1116 + info->cstate = PPTP_CALL_IN_REP;
1117 + info->pns_call_id = ntohs(pptpReq.icack->callID);
1120 + case PPTP_CALL_CLEAR_REQUEST:
1121 + /* client requests hangup of call */
1122 + if (info->sstate != PPTP_SESSION_CONFIRMED) {
1123 + DEBUGP("CLEAR_CALL but no session\n");
1126 + /* FUTURE: iterate over all calls and check if
1127 + * call ID is valid. We don't do this without newnat,
1128 + * because we only know about last call */
1129 + info->cstate = PPTP_CALL_CLEAR_REQ;
1131 + case PPTP_SET_LINK_INFO:
1133 + case PPTP_ECHO_REQUEST:
1134 + case PPTP_ECHO_REPLY:
1135 + /* I don't have to explain these ;) */
1138 + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
1139 + strMName[msg]:strMName[0], msg);
1140 + /* unknown: no need to create GRE masq table entry */
1148 +/* track caller id inside control connection, call expect_related */
1150 +conntrack_pptp_help(const struct iphdr *iph, size_t len,
1151 + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
1154 + struct pptp_pkt_hdr *pptph;
1156 + struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
1157 + u_int32_t tcplen = len - iph->ihl * 4;
1158 + u_int32_t datalen = tcplen - tcph->doff * 4;
1160 + int dir = CTINFO2DIR(ctinfo);
1161 + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
1163 + int oldsstate, oldcstate;
1166 + /* don't do any tracking before tcp handshake complete */
1167 + if (ctinfo != IP_CT_ESTABLISHED
1168 + && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
1169 + DEBUGP("ctinfo = %u, skipping\n", ctinfo);
1173 + /* not a complete TCP header? */
1174 + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
1175 + DEBUGP("tcplen = %u\n", tcplen);
1179 + /* checksum invalid? */
1180 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
1181 + csum_partial((char *) tcph, tcplen, 0))) {
1182 + printk(KERN_NOTICE __FILE__ ": bad csum\n");
1183 + /* W2K PPTP server sends TCP packets with wrong checksum :(( */
1184 + //return NF_ACCEPT;
1187 + if (tcph->fin || tcph->rst) {
1188 + DEBUGP("RST/FIN received, timeouting GRE\n");
1189 + /* can't do this after real newnat */
1190 + info->cstate = PPTP_CALL_NONE;
1192 + /* untrack this call id, unexpect GRE packets */
1193 + pptp_timeout_related(ct);
1197 + pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
1198 + datalimit = (void *) pptph + datalen;
1200 + /* not a full pptp packet header? */
1201 + if ((void *) pptph+sizeof(*pptph) >= datalimit) {
1202 + DEBUGP("no full PPTP header, can't track\n");
1206 + /* if it's not a control message we can't do anything with it */
1207 + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
1208 + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
1209 + DEBUGP("not a control packet\n");
1213 + oldsstate = info->sstate;
1214 + oldcstate = info->cstate;
1216 + LOCK_BH(&ip_pptp_lock);
1218 + /* FIXME: We just blindly assume that the control connection is always
1219 + * established from PNS->PAC. However, RFC makes no guarantee */
1220 + if (dir == IP_CT_DIR_ORIGINAL)
1221 + /* client -> server (PNS -> PAC) */
1222 + ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
1224 + /* server -> client (PAC -> PNS) */
1225 + ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
1226 + DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
1227 + oldsstate, info->sstate, oldcstate, info->cstate);
1228 + UNLOCK_BH(&ip_pptp_lock);
1233 +/* control protocol helper */
1234 +static struct ip_conntrack_helper pptp = {
1235 + .list = { NULL, NULL },
1237 + .flags = IP_CT_HELPER_F_REUSE_EXPECT,
1238 + .me = THIS_MODULE,
1239 + .max_expected = 2,
1241 + .tuple = { .src = { .ip = 0,
1242 + .u = { .tcp = { .port =
1243 + __constant_htons(PPTP_CONTROL_PORT) } }
1246 + .u = { .all = 0 },
1247 + .protonum = IPPROTO_TCP
1250 + .mask = { .src = { .ip = 0,
1251 + .u = { .tcp = { .port = 0xffff } }
1254 + .u = { .all = 0 },
1255 + .protonum = 0xffff
1258 + .help = conntrack_pptp_help
1261 +/* ip_conntrack_pptp initialization */
1262 +static int __init init(void)
1266 + DEBUGP(__FILE__ ": registering helper\n");
1267 + if ((retcode = ip_conntrack_helper_register(&pptp))) {
1268 + printk(KERN_ERR "Unable to register conntrack application "
1269 + "helper for pptp: %d\n", retcode);
1273 + printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
1277 +static void __exit fini(void)
1279 + ip_conntrack_helper_unregister(&pptp);
1280 + printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
1286 +EXPORT_SYMBOL(ip_pptp_lock);
1287 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux-2.6.0/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
1288 --- linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1970-01-01 01:00:00.000000000 +0100
1289 +++ linux-2.6.0/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2003-11-17 09:09:34.000000000 +0100
1291 +#ifndef _IP_CT_PPTP_PRIV_H
1292 +#define _IP_CT_PPTP_PRIV_H
1294 +/* PptpControlMessageType names */
1295 +static const char *strMName[] = {
1296 + "UNKNOWN_MESSAGE",
1297 + "START_SESSION_REQUEST",
1298 + "START_SESSION_REPLY",
1299 + "STOP_SESSION_REQUEST",
1300 + "STOP_SESSION_REPLY",
1303 + "OUT_CALL_REQUEST",
1305 + "IN_CALL_REQUEST",
1307 + "IN_CALL_CONNECT",
1308 + "CALL_CLEAR_REQUEST",
1309 + "CALL_DISCONNECT_NOTIFY",
1310 + "WAN_ERROR_NOTIFY",
1315 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux-2.6.0/net/ipv4/netfilter/ip_conntrack_proto_gre.c
1316 --- linux-2.6.0.org/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
1317 +++ linux-2.6.0/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2003-11-17 09:09:34.000000000 +0100
1320 + * ip_conntrack_proto_gre.c - Version 1.2
1322 + * Connection tracking protocol helper module for GRE.
1324 + * GRE is a generic encapsulation protocol, which is generally not very
1325 + * suited for NAT, as it has no protocol-specific part as port numbers.
1327 + * It has an optional key field, which may help us distinguishing two
1328 + * connections between the same two hosts.
1330 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
1332 + * PPTP is built on top of a modified version of GRE, and has a mandatory
1333 + * field called "CallID", which serves us for the same purpose as the key
1334 + * field in plain GRE.
1336 + * Documentation about PPTP can be found in RFC 2637
1338 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1340 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1344 +#include <linux/config.h>
1345 +#include <linux/module.h>
1346 +#include <linux/types.h>
1347 +#include <linux/timer.h>
1348 +#include <linux/netfilter.h>
1349 +#include <linux/ip.h>
1350 +#include <linux/in.h>
1351 +#include <linux/list.h>
1353 +#include <linux/netfilter_ipv4/lockhelp.h>
1355 +DECLARE_RWLOCK(ip_ct_gre_lock);
1356 +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
1357 +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
1359 +#include <linux/netfilter_ipv4/listhelp.h>
1360 +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
1361 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1362 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
1364 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1365 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1367 +MODULE_LICENSE("GPL");
1368 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1369 +MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
1371 +/* shamelessly stolen from ip_conntrack_proto_udp.c */
1372 +#define GRE_TIMEOUT (30*HZ)
1373 +#define GRE_STREAM_TIMEOUT (180*HZ)
1376 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1377 + ": " format, ## args)
1378 +#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
1379 + NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
1380 + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \
1381 + (x)->dst.u.gre.version, \
1382 + ntohs((x)->dst.u.gre.protocol))
1384 +#define DEBUGP(x, args...)
1385 +#define DUMP_TUPLE_GRE(x)
1388 +/* GRE KEYMAP HANDLING FUNCTIONS */
1389 +static LIST_HEAD(gre_keymap_list);
1391 +static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
1392 + const struct ip_conntrack_tuple *t)
1394 + return ((km->tuple.src.ip == t->src.ip) &&
1395 + (km->tuple.dst.ip == t->dst.ip) &&
1396 + (km->tuple.dst.protonum == t->dst.protonum) &&
1397 + (km->tuple.dst.u.all == t->dst.u.all));
1400 +/* look up the source key for a given tuple */
1401 +static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
1403 + struct ip_ct_gre_keymap *km;
1406 + READ_LOCK(&ip_ct_gre_lock);
1407 + km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
1408 + struct ip_ct_gre_keymap *, t);
1410 + READ_UNLOCK(&ip_ct_gre_lock);
1414 + key = km->tuple.src.u.gre.key;
1415 + READ_UNLOCK(&ip_ct_gre_lock);
1420 +/* add a single keymap entry, associate with specified expect */
1421 +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
1422 + struct ip_conntrack_tuple *t, int reply)
1424 + struct ip_ct_gre_keymap *km;
1426 + km = kmalloc(sizeof(*km), GFP_ATOMIC);
1430 + /* initializing list head should be sufficient */
1431 + memset(km, 0, sizeof(*km));
1433 + memcpy(&km->tuple, t, sizeof(*t));
1436 + exp->proto.gre.keymap_orig = km;
1438 + exp->proto.gre.keymap_reply = km;
1440 + DEBUGP("adding new entry %p: ", km);
1441 + DUMP_TUPLE_GRE(&km->tuple);
1443 + WRITE_LOCK(&ip_ct_gre_lock);
1444 + list_append(&gre_keymap_list, km);
1445 + WRITE_UNLOCK(&ip_ct_gre_lock);
1450 +/* change the tuple of a keymap entry (used by nat helper) */
1451 +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
1452 + struct ip_conntrack_tuple *t)
1454 + DEBUGP("changing entry %p to: ", km);
1455 + DUMP_TUPLE_GRE(t);
1457 + WRITE_LOCK(&ip_ct_gre_lock);
1458 + memcpy(&km->tuple, t, sizeof(km->tuple));
1459 + WRITE_UNLOCK(&ip_ct_gre_lock);
1462 +/* destroy the keymap entries associated with specified expect */
1463 +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
1465 + DEBUGP("entering for exp %p\n", exp);
1466 + WRITE_LOCK(&ip_ct_gre_lock);
1467 + if (exp->proto.gre.keymap_orig) {
1468 + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
1469 + list_del(&exp->proto.gre.keymap_orig->list);
1470 + kfree(exp->proto.gre.keymap_orig);
1471 + exp->proto.gre.keymap_orig = NULL;
1473 + if (exp->proto.gre.keymap_reply) {
1474 + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
1475 + list_del(&exp->proto.gre.keymap_reply->list);
1476 + kfree(exp->proto.gre.keymap_reply);
1477 + exp->proto.gre.keymap_reply = NULL;
1479 + WRITE_UNLOCK(&ip_ct_gre_lock);
1483 +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
1485 +/* invert gre part of tuple */
1486 +static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
1487 + const struct ip_conntrack_tuple *orig)
1489 + tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol;
1490 + tuple->dst.u.gre.version = orig->dst.u.gre.version;
1492 + tuple->dst.u.gre.key = orig->src.u.gre.key;
1493 + tuple->src.u.gre.key = orig->dst.u.gre.key;
1498 +/* gre hdr info to tuple */
1499 +static int gre_pkt_to_tuple(const void *datah, size_t datalen,
1500 + struct ip_conntrack_tuple *tuple)
1502 + struct gre_hdr *grehdr = (struct gre_hdr *) datah;
1503 + struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
1506 + /* core guarantees 8 protocol bytes, no need for size check */
1508 + tuple->dst.u.gre.version = grehdr->version;
1509 + tuple->dst.u.gre.protocol = grehdr->protocol;
1511 + switch (grehdr->version) {
1512 + case GRE_VERSION_1701:
1513 + if (!grehdr->key) {
1514 + DEBUGP("Can't track GRE without key\n");
1517 + tuple->dst.u.gre.key = *(gre_key(grehdr));
1520 + case GRE_VERSION_PPTP:
1521 + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
1522 + DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
1525 + tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
1529 + printk(KERN_WARNING "unknown GRE version %hu\n",
1530 + tuple->dst.u.gre.version);
1534 + srckey = gre_keymap_lookup(tuple);
1537 + DEBUGP("found src key %x for tuple ", ntohl(srckey));
1538 + DUMP_TUPLE_GRE(tuple);
1540 + tuple->src.u.gre.key = srckey;
1545 +/* print gre part of tuple */
1546 +static unsigned int gre_print_tuple(char *buffer,
1547 + const struct ip_conntrack_tuple *tuple)
1549 + return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ",
1550 + tuple->dst.u.gre.version,
1551 + ntohs(tuple->dst.u.gre.protocol),
1552 + ntohl(tuple->src.u.gre.key),
1553 + ntohl(tuple->dst.u.gre.key));
1556 +/* print private data for conntrack */
1557 +static unsigned int gre_print_conntrack(char *buffer,
1558 + const struct ip_conntrack *ct)
1560 + return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
1561 + (ct->proto.gre.timeout / HZ),
1562 + (ct->proto.gre.stream_timeout / HZ));
1565 +/* Returns verdict for packet, and may modify conntrack */
1566 +static int gre_packet(struct ip_conntrack *ct,
1567 + struct iphdr *iph, size_t len,
1568 + enum ip_conntrack_info conntrackinfo)
1570 + /* If we've seen traffic both ways, this is a GRE connection.
1571 + * Extend timeout. */
1572 + if (ct->status & IPS_SEEN_REPLY) {
1573 + ip_ct_refresh(ct, ct->proto.gre.stream_timeout);
1574 + /* Also, more likely to be important, and not a probe. */
1575 + set_bit(IPS_ASSURED_BIT, &ct->status);
1577 + ip_ct_refresh(ct, ct->proto.gre.timeout);
1582 +/* Called when a new connection for this protocol found. */
1583 +static int gre_new(struct ip_conntrack *ct,
1584 + struct iphdr *iph, size_t len)
1587 + DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
1589 + /* initialize to sane value. Ideally a conntrack helper
1590 + * (e.g. in case of pptp) is increasing them */
1591 + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
1592 + ct->proto.gre.timeout = GRE_TIMEOUT;
1597 +/* Called when a conntrack entry has already been removed from the hashes
1598 + * and is about to be deleted from memory */
1599 +static void gre_destroy(struct ip_conntrack *ct)
1601 + struct ip_conntrack_expect *master = ct->master;
1603 + DEBUGP(" entering\n");
1606 + DEBUGP("no master exp for ct %p\n", ct);
1610 + ip_ct_gre_keymap_destroy(master);
1613 +/* protocol helper struct */
1614 +static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
1619 + gre_print_conntrack,
1626 +/* ip_conntrack_proto_gre initialization */
1627 +static int __init init(void)
1631 + if ((retcode = ip_conntrack_protocol_register(&gre))) {
1632 + printk(KERN_ERR "Unable to register conntrack protocol "
1633 + "helper for gre: %d\n", retcode);
1640 +static void __exit fini(void)
1642 + struct list_head *pos, *n;
1644 + /* delete all keymap entries */
1645 + WRITE_LOCK(&ip_ct_gre_lock);
1646 + list_for_each_safe(pos, n, &gre_keymap_list) {
1647 + DEBUGP("deleting keymap %p at module unload time\n", pos);
1651 + WRITE_UNLOCK(&ip_ct_gre_lock);
1653 + ip_conntrack_protocol_unregister(&gre);
1656 +EXPORT_SYMBOL(ip_ct_gre_keymap_add);
1657 +EXPORT_SYMBOL(ip_ct_gre_keymap_change);
1658 +EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
1662 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.0/net/ipv4/netfilter/ip_nat_core.c
1663 --- linux-2.6.0.org/net/ipv4/netfilter/ip_nat_core.c 2003-12-18 03:58:16.000000000 +0100
1664 +++ linux-2.6.0/net/ipv4/netfilter/ip_nat_core.c 2003-12-19 14:14:23.000000000 +0100
1666 *tuple = *orig_tuple;
1667 while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
1669 - DEBUGP("Found best for "); DUMP_TUPLE(tuple);
1670 + DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple);
1671 /* 3) The per-protocol part of the manip is made to
1672 map into the range to make a unique tuple. */
1675 HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
1677 DEBUGP("Original: ");
1678 - DUMP_TUPLE(&orig_tp);
1679 + DUMP_TUPLE_RAW(&orig_tp);
1681 - DUMP_TUPLE(&new_tuple);
1682 + DUMP_TUPLE_RAW(&new_tuple);
1685 /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
1686 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/ip_nat_pptp.c linux-2.6.0/net/ipv4/netfilter/ip_nat_pptp.c
1687 --- linux-2.6.0.org/net/ipv4/netfilter/ip_nat_pptp.c 1970-01-01 01:00:00.000000000 +0100
1688 +++ linux-2.6.0/net/ipv4/netfilter/ip_nat_pptp.c 2003-11-17 09:09:34.000000000 +0100
1691 + * ip_nat_pptp.c - Version 1.5
1693 + * NAT support for PPTP (Point to Point Tunneling Protocol).
1694 + * PPTP is a a protocol for creating virtual private networks.
1695 + * It is a specification defined by Microsoft and some vendors
1696 + * working with Microsoft. PPTP is built on top of a modified
1697 + * version of the Internet Generic Routing Encapsulation Protocol.
1698 + * GRE is defined in RFC 1701 and RFC 1702. Documentation of
1699 + * PPTP can be found in RFC 2637
1701 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
1703 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
1705 + * TODO: - Support for multiple calls within one session
1706 + * (needs netfilter newnat code)
1707 + * - NAT to a unique tuple, not to TCP source port
1708 + * (needs netfilter tuple reservation)
1711 + * 2002-02-10 - Version 1.3
1712 + * - Use ip_nat_mangle_tcp_packet() because of cloned skb's
1713 + * in local connections (Philip Craig <philipc@snapgear.com>)
1714 + * - add checks for magicCookie and pptp version
1715 + * - make argument list of pptp_{out,in}bound_packet() shorter
1716 + * - move to C99 style initializers
1717 + * - print version number at module loadtime
1718 + * 2003-09-22 - Version 1.5
1719 + * - use SNATed tcp sourceport as callid, since we get called before
1720 + * TCP header is mangled (Philip Craig <philipc@snapgear.com>)
1724 +#include <linux/config.h>
1725 +#include <linux/module.h>
1726 +#include <linux/ip.h>
1727 +#include <linux/tcp.h>
1728 +#include <net/tcp.h>
1729 +#include <linux/netfilter_ipv4/ip_nat.h>
1730 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
1731 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
1732 +#include <linux/netfilter_ipv4/ip_nat_pptp.h>
1733 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
1734 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
1735 +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1737 +#define IP_NAT_PPTP_VERSION "1.5"
1739 +MODULE_LICENSE("GPL");
1740 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
1741 +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
1745 +#include "ip_conntrack_pptp_priv.h"
1746 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
1747 + ": " format, ## args)
1749 +#define DEBUGP(format, args...)
1752 +static unsigned int
1753 +pptp_nat_expected(struct sk_buff **pskb,
1754 + unsigned int hooknum,
1755 + struct ip_conntrack *ct,
1756 + struct ip_nat_info *info)
1758 + struct ip_conntrack *master = master_ct(ct);
1759 + struct ip_nat_multi_range mr;
1760 + struct ip_ct_pptp_master *ct_pptp_info;
1761 + struct ip_nat_pptp *nat_pptp_info;
1762 + u_int32_t newip, newcid;
1765 + IP_NF_ASSERT(info);
1766 + IP_NF_ASSERT(master);
1767 + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
1769 + DEBUGP("we have a connection!\n");
1771 + LOCK_BH(&ip_pptp_lock);
1772 + ct_pptp_info = &master->help.ct_pptp_info;
1773 + nat_pptp_info = &master->nat.help.nat_pptp_info;
1775 + /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
1776 + * (unmanipulated) values */
1777 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
1778 + DEBUGP("completing tuples with NAT info \n");
1779 + /* we can do this, since we're unconfirmed */
1780 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1781 + htonl(ct_pptp_info->pac_call_id)) {
1782 + /* assume PNS->PAC */
1783 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1784 + htonl(nat_pptp_info->pns_call_id);
1785 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1786 + htonl(nat_pptp_info->pns_call_id);
1787 + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
1788 + newcid = htonl(nat_pptp_info->pac_call_id);
1790 + /* assume PAC->PNS */
1791 + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
1792 + htonl(nat_pptp_info->pac_call_id);
1793 + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
1794 + htonl(nat_pptp_info->pac_call_id);
1795 + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1796 + newcid = htonl(nat_pptp_info->pns_call_id);
1799 + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
1800 + htonl(ct_pptp_info->pac_call_id)) {
1801 + /* assume PNS->PAC */
1802 + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1803 + newcid = htonl(ct_pptp_info->pns_call_id);
1806 + /* assume PAC->PNS */
1807 + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
1808 + newcid = htonl(ct_pptp_info->pac_call_id);
1813 + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
1814 + mr.range[0].min_ip = mr.range[0].max_ip = newip;
1815 + mr.range[0].min = mr.range[0].max =
1816 + ((union ip_conntrack_manip_proto ) { newcid });
1817 + DEBUGP("change ip to %u.%u.%u.%u\n",
1819 + DEBUGP("change key to 0x%x\n", ntohl(newcid));
1820 + ret = ip_nat_setup_info(ct, &mr, hooknum);
1822 + UNLOCK_BH(&ip_pptp_lock);
1828 +/* outbound packets == from PNS to PAC */
1829 +static inline unsigned int
1830 +pptp_outbound_pkt(struct sk_buff **pskb,
1831 + struct ip_conntrack *ct,
1832 + enum ip_conntrack_info ctinfo,
1833 + struct ip_conntrack_expect *exp)
1836 + struct iphdr *iph = (*pskb)->nh.iph;
1837 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1838 + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
1839 + ((void *)tcph + tcph->doff*4);
1841 + struct PptpControlHeader *ctlh;
1842 + union pptp_ctrl_union pptpReq;
1843 + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
1844 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
1846 + u_int16_t msg, *cid = NULL, new_callid;
1848 + /* FIXME: size checks !!! */
1849 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
1850 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
1852 + new_callid = htons(ct_pptp_info->pns_call_id);
1854 + switch (msg = ntohs(ctlh->messageType)) {
1855 + case PPTP_OUT_CALL_REQUEST:
1856 + cid = &pptpReq.ocreq->callID;
1857 + /* FIXME: ideally we would want to reserve a call ID
1858 + * here. current netfilter NAT core is not able to do
1859 + * this :( For now we use TCP source port. This breaks
1860 + * multiple calls within one control session */
1862 + /* save original call ID in nat_info */
1863 + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
1865 + /* don't use tcph->source since we are at a DSTmanip
1866 + * hook (e.g. PREROUTING) and pkt is not mangled yet */
1867 + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
1869 + /* save new call ID in ct info */
1870 + ct_pptp_info->pns_call_id = ntohs(new_callid);
1872 + case PPTP_IN_CALL_REPLY:
1873 + cid = &pptpReq.icreq->callID;
1875 + case PPTP_CALL_CLEAR_REQUEST:
1876 + cid = &pptpReq.clrreq->callID;
1879 + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
1880 + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
1881 + /* fall through */
1883 + case PPTP_SET_LINK_INFO:
1884 + /* only need to NAT in case PAC is behind NAT box */
1885 + case PPTP_START_SESSION_REQUEST:
1886 + case PPTP_START_SESSION_REPLY:
1887 + case PPTP_STOP_SESSION_REQUEST:
1888 + case PPTP_STOP_SESSION_REPLY:
1889 + case PPTP_ECHO_REQUEST:
1890 + case PPTP_ECHO_REPLY:
1891 + /* no need to alter packet */
1895 + IP_NF_ASSERT(cid);
1897 + DEBUGP("altering call id from 0x%04x to 0x%04x\n",
1898 + ntohs(*cid), ntohs(new_callid));
1900 + /* mangle packet */
1901 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
1902 + sizeof(new_callid), (char *)&new_callid,
1903 + sizeof(new_callid));
1908 +/* inbound packets == from PAC to PNS */
1909 +static inline unsigned int
1910 +pptp_inbound_pkt(struct sk_buff **pskb,
1911 + struct ip_conntrack *ct,
1912 + enum ip_conntrack_info ctinfo,
1913 + struct ip_conntrack_expect *oldexp)
1915 + struct iphdr *iph = (*pskb)->nh.iph;
1916 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
1917 + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
1918 + ((void *)tcph + tcph->doff*4);
1920 + struct PptpControlHeader *ctlh;
1921 + union pptp_ctrl_union pptpReq;
1922 + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
1923 + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
1925 + u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
1926 + u_int32_t old_dst_ip;
1928 + struct ip_conntrack_tuple t, inv_t;
1929 + struct ip_conntrack_tuple *orig_t, *reply_t;
1931 + /* FIXME: size checks !!! */
1932 + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
1933 + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
1935 + new_pcid = htons(nat_pptp_info->pns_call_id);
1937 + switch (msg = ntohs(ctlh->messageType)) {
1938 + case PPTP_OUT_CALL_REPLY:
1939 + pcid = &pptpReq.ocack->peersCallID;
1940 + cid = &pptpReq.ocack->callID;
1942 + DEBUGP("outcall but no expectation\n");
1945 + old_dst_ip = oldexp->tuple.dst.ip;
1946 + t = oldexp->tuple;
1947 + invert_tuplepr(&inv_t, &t);
1949 + /* save original PAC call ID in nat_info */
1950 + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
1952 + /* alter expectation */
1953 + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
1954 + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
1955 + if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
1956 + /* expectation for PNS->PAC direction */
1957 + t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
1958 + t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
1959 + inv_t.src.ip = reply_t->src.ip;
1960 + inv_t.dst.ip = reply_t->dst.ip;
1961 + inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
1962 + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
1964 + /* expectation for PAC->PNS direction */
1965 + t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
1966 + t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
1967 + inv_t.src.ip = orig_t->src.ip;
1968 + inv_t.dst.ip = orig_t->dst.ip;
1969 + inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
1970 + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
1973 + if (!ip_conntrack_change_expect(oldexp, &t)) {
1974 + DEBUGP("successfully changed expect\n");
1976 + DEBUGP("can't change expect\n");
1978 + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t);
1979 + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t);
1981 + case PPTP_IN_CALL_CONNECT:
1982 + pcid = &pptpReq.iccon->peersCallID;
1985 + old_dst_ip = oldexp->tuple.dst.ip;
1986 + t = oldexp->tuple;
1988 + /* alter expectation, no need for callID */
1989 + if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
1990 + /* expectation for PNS->PAC direction */
1991 + t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1993 + /* expectation for PAC->PNS direction */
1994 + t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1997 + if (!ip_conntrack_change_expect(oldexp, &t)) {
1998 + DEBUGP("successfully changed expect\n");
2000 + DEBUGP("can't change expect\n");
2003 + case PPTP_IN_CALL_REQUEST:
2004 + /* only need to nat in case PAC is behind NAT box */
2006 + case PPTP_WAN_ERROR_NOTIFY:
2007 + pcid = &pptpReq.wanerr->peersCallID;
2009 + case PPTP_CALL_DISCONNECT_NOTIFY:
2010 + pcid = &pptpReq.disc->callID;
2014 + DEBUGP("unknown inbound packet %s\n",
2015 + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
2016 + /* fall through */
2018 + case PPTP_START_SESSION_REQUEST:
2019 + case PPTP_START_SESSION_REPLY:
2020 + case PPTP_STOP_SESSION_REQUEST:
2021 + case PPTP_STOP_SESSION_REPLY:
2022 + case PPTP_ECHO_REQUEST:
2023 + case PPTP_ECHO_REPLY:
2024 + /* no need to alter packet */
2028 + /* mangle packet */
2029 + IP_NF_ASSERT(pcid);
2030 + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
2031 + ntohs(*pcid), ntohs(new_pcid));
2032 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
2033 + sizeof(new_pcid), (char *)&new_pcid,
2034 + sizeof(new_pcid));
2037 + IP_NF_ASSERT(cid);
2038 + DEBUGP("altering call id from 0x%04x to 0x%04x\n",
2039 + ntohs(*cid), ntohs(new_cid));
2040 + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
2041 + (void *)cid - (void *)pptph,
2042 + sizeof(new_cid), (char *)&new_cid,
2046 + /* great, at least we don't need to resize packets */
2051 +static unsigned int tcp_help(struct ip_conntrack *ct,
2052 + struct ip_conntrack_expect *exp,
2053 + struct ip_nat_info *info,
2054 + enum ip_conntrack_info ctinfo,
2055 + unsigned int hooknum, struct sk_buff **pskb)
2057 + struct iphdr *iph = (*pskb)->nh.iph;
2058 + struct tcphdr *tcph = (void *) iph + iph->ihl*4;
2059 + unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
2060 + struct pptp_pkt_hdr *pptph;
2064 + DEBUGP("entering\n");
2066 + /* Only mangle things once: DST for original direction
2067 + and SRC for reply direction. */
2068 + dir = CTINFO2DIR(ctinfo);
2069 + if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
2070 + && dir == IP_CT_DIR_ORIGINAL)
2071 + || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
2072 + && dir == IP_CT_DIR_REPLY))) {
2073 + DEBUGP("Not touching dir %s at hook %s\n",
2074 + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
2075 + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
2076 + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
2077 + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
2078 + : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
2082 + /* if packet is too small, just skip it */
2083 + if (datalen < sizeof(struct pptp_pkt_hdr)+
2084 + sizeof(struct PptpControlHeader)) {
2085 + DEBUGP("pptp packet too short\n");
2089 + pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
2091 + /* if it's not a control message, we can't handle it */
2092 + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
2093 + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
2094 + DEBUGP("not a pptp control packet\n");
2098 + LOCK_BH(&ip_pptp_lock);
2100 + if (dir == IP_CT_DIR_ORIGINAL) {
2101 + /* reuqests sent by client to server (PNS->PAC) */
2102 + pptp_outbound_pkt(pskb, ct, ctinfo, exp);
2104 + /* response from the server to the client (PAC->PNS) */
2105 + pptp_inbound_pkt(pskb, ct, ctinfo, exp);
2108 + UNLOCK_BH(&ip_pptp_lock);
2113 +/* nat helper struct for control connection */
2114 +static struct ip_nat_helper pptp_tcp_helper = {
2115 + .list = { NULL, NULL },
2117 + .flags = IP_NAT_HELPER_F_ALWAYS,
2118 + .me = THIS_MODULE,
2119 + .tuple = { .src = { .ip = 0,
2120 + .u = { .tcp = { .port =
2121 + __constant_htons(PPTP_CONTROL_PORT) }
2125 + .u = { .all = 0 },
2126 + .protonum = IPPROTO_TCP
2130 + .mask = { .src = { .ip = 0,
2131 + .u = { .tcp = { .port = 0xFFFF } }
2134 + .u = { .all = 0 },
2135 + .protonum = 0xFFFF
2139 + .expect = pptp_nat_expected
2143 +static int __init init(void)
2145 + DEBUGP("%s: registering NAT helper\n", __FILE__);
2146 + if (ip_nat_helper_register(&pptp_tcp_helper)) {
2147 + printk(KERN_ERR "Unable to register NAT application helper "
2152 + printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
2156 +static void __exit fini(void)
2158 + DEBUGP("cleanup_module\n" );
2159 + ip_nat_helper_unregister(&pptp_tcp_helper);
2160 + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
2165 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.6.0/net/ipv4/netfilter/ip_nat_proto_gre.c
2166 --- linux-2.6.0.org/net/ipv4/netfilter/ip_nat_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
2167 +++ linux-2.6.0/net/ipv4/netfilter/ip_nat_proto_gre.c 2003-11-17 09:09:34.000000000 +0100
2170 + * ip_nat_proto_gre.c - Version 1.2
2172 + * NAT protocol helper module for GRE.
2174 + * GRE is a generic encapsulation protocol, which is generally not very
2175 + * suited for NAT, as it has no protocol-specific part as port numbers.
2177 + * It has an optional key field, which may help us distinguishing two
2178 + * connections between the same two hosts.
2180 + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
2182 + * PPTP is built on top of a modified version of GRE, and has a mandatory
2183 + * field called "CallID", which serves us for the same purpose as the key
2184 + * field in plain GRE.
2186 + * Documentation about PPTP can be found in RFC 2637
2188 + * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
2190 + * Development of this code funded by Astaro AG (http://www.astaro.com/)
2194 +#include <linux/config.h>
2195 +#include <linux/module.h>
2196 +#include <linux/ip.h>
2197 +#include <linux/netfilter_ipv4/ip_nat.h>
2198 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
2199 +#include <linux/netfilter_ipv4/ip_nat_protocol.h>
2200 +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
2202 +MODULE_LICENSE("GPL");
2203 +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
2204 +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
2207 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
2208 + ": " format, ## args)
2210 +#define DEBUGP(x, args...)
2213 +/* is key in given range between min and max */
2215 +gre_in_range(const struct ip_conntrack_tuple *tuple,
2216 + enum ip_nat_manip_type maniptype,
2217 + const union ip_conntrack_manip_proto *min,
2218 + const union ip_conntrack_manip_proto *max)
2222 + if (maniptype == IP_NAT_MANIP_SRC)
2223 + key = tuple->src.u.gre.key;
2225 + key = tuple->dst.u.gre.key;
2227 + return ntohl(key) >= ntohl(min->gre.key)
2228 + && ntohl(key) <= ntohl(max->gre.key);
2231 +/* generate unique tuple ... */
2233 +gre_unique_tuple(struct ip_conntrack_tuple *tuple,
2234 + const struct ip_nat_range *range,
2235 + enum ip_nat_manip_type maniptype,
2236 + const struct ip_conntrack *conntrack)
2238 + u_int32_t min, i, range_size;
2239 + u_int32_t key = 0, *keyptr;
2241 + if (maniptype == IP_NAT_MANIP_SRC)
2242 + keyptr = &tuple->src.u.gre.key;
2244 + keyptr = &tuple->dst.u.gre.key;
2246 + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
2248 + switch (tuple->dst.u.gre.version) {
2250 + DEBUGP("NATing GRE version 0 (ct=%p)\n",
2253 + range_size = 0xffffffff;
2255 + case GRE_VERSION_PPTP:
2256 + DEBUGP("%p: NATing GRE PPTP\n",
2259 + range_size = 0xffff;
2262 + printk(KERN_WARNING "nat_gre: unknown GRE version\n");
2268 + min = ntohl(range->min.gre.key);
2269 + range_size = ntohl(range->max.gre.key) - min + 1;
2272 + DEBUGP("min = %u, range_size = %u\n", min, range_size);
2274 + for (i = 0; i < range_size; i++, key++) {
2275 + *keyptr = htonl(min + key % range_size);
2276 + if (!ip_nat_used_tuple(tuple, conntrack))
2280 + DEBUGP("%p: no NAT mapping\n", conntrack);
2285 +/* manipulate a GRE packet according to maniptype */
2287 +gre_manip_pkt(struct iphdr *iph, size_t len,
2288 + const struct ip_conntrack_manip *manip,
2289 + enum ip_nat_manip_type maniptype)
2291 + struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
2292 + struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
2294 + /* we only have destination manip of a packet, since 'source key'
2295 + * is not present in the packet itself */
2296 + if (maniptype == IP_NAT_MANIP_DST) {
2297 + /* key manipulation is always dest */
2298 + switch (greh->version) {
2301 + DEBUGP("can't nat GRE w/o key\n");
2305 + /* FIXME: Never tested this code... */
2306 + *(gre_csum(greh)) =
2307 + ip_nat_cheat_check(~*(gre_key(greh)),
2309 + *(gre_csum(greh)));
2311 + *(gre_key(greh)) = manip->u.gre.key;
2313 + case GRE_VERSION_PPTP:
2314 + DEBUGP("call_id -> 0x%04x\n",
2315 + ntohl(manip->u.gre.key));
2316 + pgreh->call_id = htons(ntohl(manip->u.gre.key));
2319 + DEBUGP("can't nat unknown GRE version\n");
2325 +/* print out a nat tuple */
2326 +static unsigned int
2327 +gre_print(char *buffer,
2328 + const struct ip_conntrack_tuple *match,
2329 + const struct ip_conntrack_tuple *mask)
2331 + unsigned int len = 0;
2333 + if (mask->dst.u.gre.version)
2334 + len += sprintf(buffer + len, "version=%d ",
2335 + ntohs(match->dst.u.gre.version));
2337 + if (mask->dst.u.gre.protocol)
2338 + len += sprintf(buffer + len, "protocol=0x%x ",
2339 + ntohs(match->dst.u.gre.protocol));
2341 + if (mask->src.u.gre.key)
2342 + len += sprintf(buffer + len, "srckey=0x%x ",
2343 + ntohl(match->src.u.gre.key));
2345 + if (mask->dst.u.gre.key)
2346 + len += sprintf(buffer + len, "dstkey=0x%x ",
2347 + ntohl(match->src.u.gre.key));
2352 +/* print a range of keys */
2353 +static unsigned int
2354 +gre_print_range(char *buffer, const struct ip_nat_range *range)
2356 + if (range->min.gre.key != 0
2357 + || range->max.gre.key != 0xFFFF) {
2358 + if (range->min.gre.key == range->max.gre.key)
2359 + return sprintf(buffer, "key 0x%x ",
2360 + ntohl(range->min.gre.key));
2362 + return sprintf(buffer, "keys 0x%u-0x%u ",
2363 + ntohl(range->min.gre.key),
2364 + ntohl(range->max.gre.key));
2369 +/* nat helper struct */
2370 +static struct ip_nat_protocol gre =
2371 + { { NULL, NULL }, "GRE", IPPROTO_GRE,
2379 +static int __init init(void)
2381 + if (ip_nat_protocol_register(&gre))
2387 +static void __exit fini(void)
2389 + ip_nat_protocol_unregister(&gre);
2394 diff -Nur linux-2.6.0.org/net/ipv4/netfilter/Kconfig linux-2.6.0/net/ipv4/netfilter/Kconfig
2395 --- linux-2.6.0.org/net/ipv4/netfilter/Kconfig 2003-12-18 03:59:25.000000000 +0100
2396 +++ linux-2.6.0/net/ipv4/netfilter/Kconfig 2003-12-19 11:37:04.565557808 +0100
2399 To compile it as a module, choose M here. If unsure, say Y.
2401 +config IP_NF_CT_PROTO_GRE
2402 + tristate " GRE protocol support"
2403 + depends on IP_NF_CONNTRACK!=n
2407 + tristate " PPTP protocol support"
2408 + depends on IP_NF_CT_PROTO_GRE!=n
2412 tristate "Userspace queueing via NETLINK"
2414 @@ -390,6 +400,18 @@
2416 # If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
2417 # or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh.
2418 +config IP_NF_NAT_PROTO_GRE
2420 + depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
2421 + default IP_NF_NAT_PROTO_GRE if IP_NF_CT_PROTO_GRE=y
2422 + default m if IP_NF_CT_PROTO_GRE=m
2424 +config IP_NF_NAT_PPTP
2426 + depends on IP_NF_CT_PROTO_GRE!=n && IP_NF_PPTP!=n && IP_NF_NAT!=n
2427 + default IP_NF_NAT_PPTP if IP_NF_PPTP=y
2428 + default m if IP_NF_PPTP=m
2430 config IP_NF_NAT_FTP
2432 depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n