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