diff -Nur linux-2.6.0-test11.org/include/linux/netfilter.h linux-2.6.0-test11/include/linux/netfilter.h --- linux-2.6.0-test11.org/include/linux/netfilter.h 2003-11-26 21:44:11.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter.h 2003-12-10 23:13:24.656327752 +0100 @@ -23,6 +23,7 @@ <= 0x2000 is used for protocol-flags. */ #define NFC_UNKNOWN 0x4000 #define NFC_ALTERED 0x8000 +#define NFC_TRACE 0x10000 #ifdef __KERNEL__ #include @@ -99,6 +100,24 @@ extern struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; +typedef void nf_logfn(unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const char *prefix); + +/* Function to register/unregister log function. */ +int nf_log_register(int pf, nf_logfn *logfn); +void nf_log_unregister(int pf, nf_logfn *logfn); + +/* Calls the registered backend logging function */ +void nf_log_packet(int pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const char *fmt, ...); + /* Activate hook; either okfn or kfree_skb called, unless a hook returns NF_STOLEN (in which case, it's up to the hook to deal with the consequences). diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_helpers.h linux-2.6.0-test11/include/linux/netfilter_helpers.h --- linux-2.6.0-test11.org/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_helpers.h 2003-12-10 23:14:12.889995120 +0100 @@ -0,0 +1,133 @@ +/* + * Helpers for netfiler modules. This file provides implementations for basic + * functions such as strncasecmp(), etc. + * + * gcc will warn for defined but unused functions, so we only include the + * functions requested. The following macros are used: + * NF_NEED_STRNCASECMP nf_strncasecmp() + * NF_NEED_STRTOU16 nf_strtou16() + * NF_NEED_STRTOU32 nf_strtou32() + */ +#ifndef _NETFILTER_HELPERS_H +#define _NETFILTER_HELPERS_H + +/* Only include these functions for kernel code. */ +#ifdef __KERNEL__ + +#include +#define iseol(c) ( (c) == '\r' || (c) == '\n' ) + +/* + * The standard strncasecmp() + */ +#ifdef NF_NEED_STRNCASECMP +static int +nf_strncasecmp(const char* s1, const char* s2, u_int32_t len) +{ + if (s1 == NULL || s2 == NULL) + { + if (s1 == NULL && s2 == NULL) + { + return 0; + } + return (s1 == NULL) ? -1 : 1; + } + while (len > 0 && tolower(*s1) == tolower(*s2)) + { + len--; + s1++; + s2++; + } + return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) ); +} +#endif /* NF_NEED_STRNCASECMP */ + +/* + * Parse a string containing a 16-bit unsigned integer. + * Returns the number of chars used, or zero if no number is found. + */ +#ifdef NF_NEED_STRTOU16 +static int +nf_strtou16(const char* pbuf, u_int16_t* pval) +{ + int n = 0; + + *pval = 0; + while (isdigit(pbuf[n])) + { + *pval = (*pval * 10) + (pbuf[n] - '0'); + n++; + } + + return n; +} +#endif /* NF_NEED_STRTOU16 */ + +/* + * Parse a string containing a 32-bit unsigned integer. + * Returns the number of chars used, or zero if no number is found. + */ +#ifdef NF_NEED_STRTOU32 +static int +nf_strtou32(const char* pbuf, u_int32_t* pval) +{ + int n = 0; + + *pval = 0; + while (pbuf[n] >= '0' && pbuf[n] <= '9') + { + *pval = (*pval * 10) + (pbuf[n] - '0'); + n++; + } + + return n; +} +#endif /* NF_NEED_STRTOU32 */ + +/* + * Given a buffer and length, advance to the next line and mark the current + * line. + */ +#ifdef NF_NEED_NEXTLINE +static int +nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) +{ + uint off = *poff; + uint physlen = 0; + + if (off >= len) + { + return 0; + } + + while (p[off] != '\n') + { + if (len-off <= 1) + { + return 0; + } + + physlen++; + off++; + } + + /* if we saw a crlf, physlen needs adjusted */ + if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') + { + physlen--; + } + + /* advance past the newline */ + off++; + + *plineoff = *poff; + *plinelen = physlen; + *poff = off; + + return 1; +} +#endif /* NF_NEED_NEXTLINE */ + +#endif /* __KERNEL__ */ + +#endif /* _NETFILTER_HELPERS_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_cuseeme.h 2003-12-10 23:13:55.776596752 +0100 @@ -0,0 +1,70 @@ +#ifndef _IP_CT_CUSEEME +#define _IP_CT_CUSEEME + +#define CUSEEME_PORT 7648 + +/* These structs come from the 2.2 ip_masq_cuseeme code... */ + +#pragma pack(1) +/* CuSeeMe data header */ +struct cu_header { + u_int16_t dest_family; + u_int16_t dest_port; + u_int32_t dest_addr; + int16_t family; + u_int16_t port; + u_int32_t addr; + u_int32_t seq; + u_int16_t msg; + u_int16_t data_type; + /* possible values: + * 1 small video + * 2 big video + * 3 audio + * 100 acknowledge connectivity when there + * is nothing else to send + * 101 OpenContinue packet + * 104 display a text message and + * disconnect (used by reflector to + * kick clients off) + * 105 display a text message (welcome + * message from reflector) + * 106 exchanged among reflectors for + * reflector interoperation + * 107 carry aux stream data when there is + * no video to piggy-back on + * 108 obsolete (used in Mac alpha version) + * 109 obsolete (used in Mac alpha version) + * 110 used for data rate control + * 111 used for data rate control + * 256 aux data control messages + * 257 aux data packets + * */ + u_int16_t packet_len; +}; + +/* Open Continue Header */ +struct oc_header { + struct cu_header cu_head; + u_int16_t client_count; /* Number of client info structs */ + u_int32_t seq_no; + char user_name[20]; + char stuff[4]; /* Flags, version stuff, etc */ +}; + +/* Client info structures */ +struct client_info { + u_int32_t address; /* Client address */ + char stuff[8]; /* Flags, pruning bitfield, packet counts, etc */ +}; +#pragma pack() + +/* This structure is per expected connection */ +struct ip_ct_cuseeme_expect { +}; + +/* This structure exists only once per master */ +struct ip_ct_cuseeme_master { +}; + +#endif /* _IP_CT_CUSEEME */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack.h 2003-11-26 21:45:37.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack.h 2003-12-10 23:22:29.227540344 +0100 @@ -51,10 +51,13 @@ #include #include +#include /* per conntrack: protocol private data */ union ip_conntrack_proto { /* insert conntrack proto private data here */ + struct ip_ct_gre_expect gre; + struct ip_ct_gre gre; struct ip_ct_tcp tcp; struct ip_ct_icmp icmp; }; @@ -64,6 +67,13 @@ }; /* Add protocol helper include file here */ +#include +#include +#include +#include +#include +#include + #include #include #include @@ -71,6 +81,13 @@ /* per expectation: application helper private data */ union ip_conntrack_expect_help { /* insert conntrack helper private data (expect) here */ + struct ip_ct_pptp_expect exp_pptp_info; + struct ip_ct_talk_expect exp_talk_info; + struct ip_ct_rtsp_master ct_rtsp_info; + struct ip_ct_rtsp_expect exp_rtsp_info; + struct ip_ct_rsh_expect exp_rsh_info; + struct ip_ct_mms_expect exp_mms_info; + struct ip_ct_h225_expect exp_h225_info; struct ip_ct_amanda_expect exp_amanda_info; struct ip_ct_ftp_expect exp_ftp_info; struct ip_ct_irc_expect exp_irc_info; @@ -85,16 +102,23 @@ /* per conntrack: application helper private data */ union ip_conntrack_help { /* insert conntrack helper private data (master) here */ + struct ip_ct_pptp_master ct_pptp_info; + struct ip_ct_talk_master ct_talk_info; + struct ip_ct_rsh_master ct_rsh_info; + struct ip_ct_mms_master ct_mms_info; + struct ip_ct_h225_master ct_h225_info; struct ip_ct_ftp_master ct_ftp_info; struct ip_ct_irc_master ct_irc_info; }; #ifdef CONFIG_IP_NF_NAT_NEEDED #include +#include /* per conntrack: nat application helper private data */ union ip_conntrack_nat_help { /* insert nat helper private data here */ + struct ip_nat_pptp nat_pptp_info; }; #endif @@ -206,6 +230,9 @@ } nat; #endif /* CONFIG_IP_NF_NAT_NEEDED */ +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + unsigned long mark; +#endif }; /* get master conntrack via master expectation */ @@ -247,6 +274,9 @@ extern void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies); +/* Kill conntrack */ +extern void ip_ct_death_by_timeout(unsigned long ul_conntrack); + /* These are for NAT. Icky. */ /* Call me when a conntrack is destroyed. */ extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack); @@ -268,6 +298,9 @@ extern unsigned int ip_conntrack_htable_size; +/* A fake conntrack entry which never vanishes. */ +extern struct ip_conntrack ip_conntrack_untracked; + /* eg. PROVIDES_CONNTRACK(ftp); */ #define PROVIDES_CONNTRACK(name) \ int needs_ip_conntrack_##name; \ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_h323.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2003-12-10 23:13:58.176231952 +0100 @@ -0,0 +1,30 @@ +#ifndef _IP_CONNTRACK_H323_H +#define _IP_CONNTRACK_H323_H +/* H.323 connection tracking. */ + +#ifdef __KERNEL__ +/* Protects H.323 related data */ +DECLARE_LOCK_EXTERN(ip_h323_lock); +#endif + +/* Default H.225 port */ +#define H225_PORT 1720 + +/* This structure is per expected connection */ +struct ip_ct_h225_expect { + u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */ + enum ip_conntrack_dir dir; /* Direction of the original connection */ + unsigned int offset; /* offset of the address in the payload */ +}; + +/* This structure exists only once per master */ +struct ip_ct_h225_master { + int is_h225; /* H.225 or H.245 connection */ +#ifdef CONFIG_IP_NF_NAT_NEEDED + enum ip_conntrack_dir dir; /* Direction of the original connection */ + u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */ + unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */ +#endif +}; + +#endif /* _IP_CONNTRACK_H323_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_mms.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_mms.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_mms.h 2003-12-10 23:14:02.755535792 +0100 @@ -0,0 +1,31 @@ +#ifndef _IP_CONNTRACK_MMS_H +#define _IP_CONNTRACK_MMS_H +/* MMS tracking. */ + +#ifdef __KERNEL__ +#include + +DECLARE_LOCK_EXTERN(ip_mms_lock); + +#define MMS_PORT 1755 +#define MMS_SRV_MSG_ID 196610 + +#define MMS_SRV_MSG_OFFSET 36 +#define MMS_SRV_UNICODE_STRING_OFFSET 60 +#define MMS_SRV_CHUNKLENLV_OFFSET 16 +#define MMS_SRV_CHUNKLENLM_OFFSET 32 +#define MMS_SRV_MESSAGELENGTH_OFFSET 8 +#endif + +/* This structure is per expected connection */ +struct ip_ct_mms_expect { + u_int32_t len; + u_int32_t padding; + u_int16_t port; +}; + +/* This structure exists only once per master */ +struct ip_ct_mms_master { +}; + +#endif /* _IP_CONNTRACK_MMS_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_pptp.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2003-11-17 09:09:34.000000000 +0100 @@ -0,0 +1,313 @@ +/* PPTP constants and structs */ +#ifndef _CONNTRACK_PPTP_H +#define _CONNTRACK_PPTP_H + +/* state of the control session */ +enum pptp_ctrlsess_state { + PPTP_SESSION_NONE, /* no session present */ + PPTP_SESSION_ERROR, /* some session error */ + PPTP_SESSION_STOPREQ, /* stop_sess request seen */ + PPTP_SESSION_REQUESTED, /* start_sess request seen */ + PPTP_SESSION_CONFIRMED, /* session established */ +}; + +/* state of the call inside the control session */ +enum pptp_ctrlcall_state { + PPTP_CALL_NONE, + PPTP_CALL_ERROR, + PPTP_CALL_OUT_REQ, + PPTP_CALL_OUT_CONF, + PPTP_CALL_IN_REQ, + PPTP_CALL_IN_REP, + PPTP_CALL_IN_CONF, + PPTP_CALL_CLEAR_REQ, +}; + + +/* conntrack private data */ +struct ip_ct_pptp_master { + enum pptp_ctrlsess_state sstate; /* session state */ + + /* everything below is going to be per-expectation in newnat, + * since there could be more than one call within one session */ + enum pptp_ctrlcall_state cstate; /* call state */ + u_int16_t pac_call_id; /* call id of PAC, host byte order */ + u_int16_t pns_call_id; /* call id of PNS, host byte order */ +}; + +/* conntrack_expect private member */ +struct ip_ct_pptp_expect { + enum pptp_ctrlcall_state cstate; /* call state */ + u_int16_t pac_call_id; /* call id of PAC */ + u_int16_t pns_call_id; /* call id of PNS */ +}; + + +#ifdef __KERNEL__ + +#include +DECLARE_LOCK_EXTERN(ip_pptp_lock); + +#define IP_CONNTR_PPTP PPTP_CONTROL_PORT + +union pptp_ctrl_union { + void *rawreq; + struct PptpStartSessionRequest *sreq; + struct PptpStartSessionReply *srep; + struct PptpStopSessionReqest *streq; + struct PptpStopSessionReply *strep; + struct PptpOutCallRequest *ocreq; + struct PptpOutCallReply *ocack; + struct PptpInCallRequest *icreq; + struct PptpInCallReply *icack; + struct PptpInCallConnected *iccon; + struct PptpClearCallRequest *clrreq; + struct PptpCallDisconnectNotify *disc; + struct PptpWanErrorNotify *wanerr; + struct PptpSetLinkInfo *setlink; +}; + + + +#define PPTP_CONTROL_PORT 1723 + +#define PPTP_PACKET_CONTROL 1 +#define PPTP_PACKET_MGMT 2 + +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d + +struct pptp_pkt_hdr { + __u16 packetLength; + __u16 packetType; + __u32 magicCookie; +}; + +/* PptpControlMessageType values */ +#define PPTP_START_SESSION_REQUEST 1 +#define PPTP_START_SESSION_REPLY 2 +#define PPTP_STOP_SESSION_REQUEST 3 +#define PPTP_STOP_SESSION_REPLY 4 +#define PPTP_ECHO_REQUEST 5 +#define PPTP_ECHO_REPLY 6 +#define PPTP_OUT_CALL_REQUEST 7 +#define PPTP_OUT_CALL_REPLY 8 +#define PPTP_IN_CALL_REQUEST 9 +#define PPTP_IN_CALL_REPLY 10 +#define PPTP_IN_CALL_CONNECT 11 +#define PPTP_CALL_CLEAR_REQUEST 12 +#define PPTP_CALL_DISCONNECT_NOTIFY 13 +#define PPTP_WAN_ERROR_NOTIFY 14 +#define PPTP_SET_LINK_INFO 15 + +#define PPTP_MSG_MAX 15 + +/* PptpGeneralError values */ +#define PPTP_ERROR_CODE_NONE 0 +#define PPTP_NOT_CONNECTED 1 +#define PPTP_BAD_FORMAT 2 +#define PPTP_BAD_VALUE 3 +#define PPTP_NO_RESOURCE 4 +#define PPTP_BAD_CALLID 5 +#define PPTP_REMOVE_DEVICE_ERROR 6 + +struct PptpControlHeader { + __u16 messageType; + __u16 reserved; +}; + +/* FramingCapability Bitmap Values */ +#define PPTP_FRAME_CAP_ASYNC 0x1 +#define PPTP_FRAME_CAP_SYNC 0x2 + +/* BearerCapability Bitmap Values */ +#define PPTP_BEARER_CAP_ANALOG 0x1 +#define PPTP_BEARER_CAP_DIGITAL 0x2 + +struct PptpStartSessionRequest { + __u16 protocolVersion; + __u8 reserved1; + __u8 reserved2; + __u32 framingCapability; + __u32 bearerCapability; + __u16 maxChannels; + __u16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStartSessionResultCode Values */ +#define PPTP_START_OK 1 +#define PPTP_START_GENERAL_ERROR 2 +#define PPTP_START_ALREADY_CONNECTED 3 +#define PPTP_START_NOT_AUTHORIZED 4 +#define PPTP_START_UNKNOWN_PROTOCOL 5 + +struct PptpStartSessionReply { + __u16 protocolVersion; + __u8 resultCode; + __u8 generalErrorCode; + __u32 framingCapability; + __u32 bearerCapability; + __u16 maxChannels; + __u16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStopReasons */ +#define PPTP_STOP_NONE 1 +#define PPTP_STOP_PROTOCOL 2 +#define PPTP_STOP_LOCAL_SHUTDOWN 3 + +struct PptpStopSessionRequest { + __u8 reason; +}; + +/* PptpStopSessionResultCode */ +#define PPTP_STOP_OK 1 +#define PPTP_STOP_GENERAL_ERROR 2 + +struct PptpStopSessionReply { + __u8 resultCode; + __u8 generalErrorCode; +}; + +struct PptpEchoRequest { + __u32 identNumber; +}; + +/* PptpEchoReplyResultCode */ +#define PPTP_ECHO_OK 1 +#define PPTP_ECHO_GENERAL_ERROR 2 + +struct PptpEchoReply { + __u32 identNumber; + __u8 resultCode; + __u8 generalErrorCode; + __u16 reserved; +}; + +/* PptpFramingType */ +#define PPTP_ASYNC_FRAMING 1 +#define PPTP_SYNC_FRAMING 2 +#define PPTP_DONT_CARE_FRAMING 3 + +/* PptpCallBearerType */ +#define PPTP_ANALOG_TYPE 1 +#define PPTP_DIGITAL_TYPE 2 +#define PPTP_DONT_CARE_BEARER_TYPE 3 + +struct PptpOutCallRequest { + __u16 callID; + __u16 callSerialNumber; + __u32 minBPS; + __u32 maxBPS; + __u32 bearerType; + __u32 framingType; + __u16 packetWindow; + __u16 packetProcDelay; + __u16 reserved1; + __u16 phoneNumberLength; + __u16 reserved2; + __u8 phoneNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpCallResultCode */ +#define PPTP_OUTCALL_CONNECT 1 +#define PPTP_OUTCALL_GENERAL_ERROR 2 +#define PPTP_OUTCALL_NO_CARRIER 3 +#define PPTP_OUTCALL_BUSY 4 +#define PPTP_OUTCALL_NO_DIAL_TONE 5 +#define PPTP_OUTCALL_TIMEOUT 6 +#define PPTP_OUTCALL_DONT_ACCEPT 7 + +struct PptpOutCallReply { + __u16 callID; + __u16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __u16 causeCode; + __u32 connectSpeed; + __u16 packetWindow; + __u16 packetProcDelay; + __u32 physChannelID; +}; + +struct PptpInCallRequest { + __u16 callID; + __u16 callSerialNumber; + __u32 callBearerType; + __u32 physChannelID; + __u16 dialedNumberLength; + __u16 dialingNumberLength; + __u8 dialedNumber[64]; + __u8 dialingNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpInCallResultCode */ +#define PPTP_INCALL_ACCEPT 1 +#define PPTP_INCALL_GENERAL_ERROR 2 +#define PPTP_INCALL_DONT_ACCEPT 3 + +struct PptpInCallReply { + __u16 callID; + __u16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __u16 packetWindow; + __u16 packetProcDelay; + __u16 reserved; +}; + +struct PptpInCallConnected { + __u16 peersCallID; + __u16 reserved; + __u32 connectSpeed; + __u16 packetWindow; + __u16 packetProcDelay; + __u32 callFramingType; +}; + +struct PptpClearCallRequest { + __u16 callID; + __u16 reserved; +}; + +struct PptpCallDisconnectNotify { + __u16 callID; + __u8 resultCode; + __u8 generalErrorCode; + __u16 causeCode; + __u16 reserved; + __u8 callStatistics[128]; +}; + +struct PptpWanErrorNotify { + __u16 peersCallID; + __u16 reserved; + __u32 crcErrors; + __u32 framingErrors; + __u32 hardwareOverRuns; + __u32 bufferOverRuns; + __u32 timeoutErrors; + __u32 alignmentErrors; +}; + +struct PptpSetLinkInfo { + __u16 peersCallID; + __u16 reserved; + __u32 sendAccm; + __u32 recvAccm; +}; + + +struct pptp_priv_data { + __u16 call_id; + __u16 mcall_id; + __u16 pcall_id; +}; + +#endif /* __KERNEL__ */ +#endif /* _CONNTRACK_PPTP_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2003-11-17 09:09:34.000000000 +0100 @@ -0,0 +1,123 @@ +#ifndef _CONNTRACK_PROTO_GRE_H +#define _CONNTRACK_PROTO_GRE_H +#include + +/* GRE PROTOCOL HEADER */ + +/* GRE Version field */ +#define GRE_VERSION_1701 0x0 +#define GRE_VERSION_PPTP 0x1 + +/* GRE Protocol field */ +#define GRE_PROTOCOL_PPTP 0x880B + +/* GRE Flags */ +#define GRE_FLAG_C 0x80 +#define GRE_FLAG_R 0x40 +#define GRE_FLAG_K 0x20 +#define GRE_FLAG_S 0x10 +#define GRE_FLAG_A 0x80 + +#define GRE_IS_C(f) ((f)&GRE_FLAG_C) +#define GRE_IS_R(f) ((f)&GRE_FLAG_R) +#define GRE_IS_K(f) ((f)&GRE_FLAG_K) +#define GRE_IS_S(f) ((f)&GRE_FLAG_S) +#define GRE_IS_A(f) ((f)&GRE_FLAG_A) + +/* GRE is a mess: Four different standards */ +struct gre_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 rec:3, + srr:1, + seq:1, + key:1, + routing:1, + csum:1, + version:3, + reserved:4, + ack:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 csum:1, + routing:1, + key:1, + seq:1, + srr:1, + rec:3, + ack:1, + reserved:4, + version:3; +#else +#error "Adjust your defines" +#endif + __u16 protocol; +}; + +/* modified GRE header for PPTP */ +struct gre_hdr_pptp { + __u8 flags; /* bitfield */ + __u8 version; /* should be GRE_VERSION_PPTP */ + __u16 protocol; /* should be GRE_PROTOCOL_PPTP */ + __u16 payload_len; /* size of ppp payload, not inc. gre header */ + __u16 call_id; /* peer's call_id for this session */ + __u32 seq; /* sequence number. Present if S==1 */ + __u32 ack; /* seq number of highest packet recieved by */ + /* sender in this session */ +}; + + +/* this is part of ip_conntrack */ +struct ip_ct_gre { + unsigned int stream_timeout; + unsigned int timeout; +}; + +/* this is part of ip_conntrack_expect */ +struct ip_ct_gre_expect { + struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; +}; + +#ifdef __KERNEL__ +struct ip_conntrack_expect; + +/* structure for original <-> reply keymap */ +struct ip_ct_gre_keymap { + struct list_head list; + + struct ip_conntrack_tuple tuple; +}; + + +/* add new tuple->key_reply pair to keymap */ +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, + struct ip_conntrack_tuple *t, + int reply); + +/* change an existing keymap entry */ +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, + struct ip_conntrack_tuple *t); + +/* delete keymap entries */ +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp); + + +/* get pointer to gre key, if present */ +static inline u_int32_t *gre_key(struct gre_hdr *greh) +{ + if (!greh->key) + return NULL; + if (greh->csum || greh->routing) + return (u_int32_t *) (greh+sizeof(*greh)+4); + return (u_int32_t *) (greh+sizeof(*greh)); +} + +/* get pointer ot gre csum, if present */ +static inline u_int16_t *gre_csum(struct gre_hdr *greh) +{ + if (!greh->csum) + return NULL; + return (u_int16_t *) (greh+sizeof(*greh)); +} + +#endif /* __KERNEL__ */ + +#endif /* _CONNTRACK_PROTO_GRE_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_quake3.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_quake3.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_quake3.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_quake3.h 2003-12-10 23:14:06.243005616 +0100 @@ -0,0 +1,21 @@ +#ifndef _IP_CT_QUAKE3 +#define _IP_CT_QUAKE3 + +/* Don't confuse with 27960, often used as the Server Port */ +#define QUAKE3_MASTER_PORT 27950 + +struct quake3_search { + const char marker[4]; /* always 0xff 0xff 0xff 0xff ? */ + const char *pattern; + size_t plen; +}; + +/* This structure is per expected connection */ +struct ip_ct_quake3_expect { +}; + +/* This structure exists only once per master */ +struct ip_ct_quake3_master { +}; + +#endif /* _IP_CT_QUAKE3 */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_rpc.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 2003-12-10 23:14:10.155410840 +0100 @@ -0,0 +1,68 @@ +/* RPC extension for IP connection tracking, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original rpc tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ip_conntrack_rpc.h,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + */ + +#include +#include +#include +#include +#include + +#include + +#ifndef _IP_CONNTRACK_RPC_H +#define _IP_CONNTRACK_RPC_H + +#define RPC_PORT 111 + + +/* Datum in RPC packets are encoded in XDR */ +#define IXDR_GET_INT32(buf) ((u_int32_t) ntohl((uint32_t)*buf)) + +/* Fast timeout, to deny DoS atacks */ +#define EXP (60 * HZ) + +/* Normal timeouts */ +#define EXPIRES (180 * HZ) + +/* For future conections RPC, using client's cache bindings + * I'll use ip_conntrack_lock to lock these lists */ + +/* This identifies each request and stores protocol */ +struct request_p { + struct list_head list; + + u_int32_t xid; + u_int32_t ip; + u_int16_t port; + + /* Protocol */ + u_int16_t proto; + + struct timer_list timeout; +}; + +static inline int request_p_cmp(const struct request_p *p, u_int32_t xid, + u_int32_t ip, u_int32_t port) { + return (p->xid == xid && p->ip == ip && p->port); + +} + +#endif /* _IP_CONNTRACK_RPC_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_rsh.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_rsh.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_rsh.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_rsh.h 2003-12-10 23:14:11.556197888 +0100 @@ -0,0 +1,35 @@ +/* RSH extension for IP connection tracking, Version 1.0 + * (C) 2002 by Ian (Larry) Latter + * based on HW's ip_conntrack_irc.c + * + * ip_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _IP_CONNTRACK_RSH_H +#define _IP_CONNTRACK_RSH_H + +#ifdef __KERNEL__ +#include + +DECLARE_LOCK_EXTERN(ip_rsh_lock); +#endif + + +#define RSH_PORT 514 + +/* This structure is per expected connection */ +struct ip_ct_rsh_expect +{ + u_int16_t port; +}; + +/* This structure exists only once per master */ +struct ip_ct_rsh_master { +}; + +#endif /* _IP_CONNTRACK_RSH_H */ + diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2003-12-10 23:14:12.890994968 +0100 @@ -0,0 +1,68 @@ +/* + * RTSP extension for IP connection tracking. + * (C) 2003 by Tom Marshall + * based on ip_conntrack_irc.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _IP_CONNTRACK_RTSP_H +#define _IP_CONNTRACK_RTSP_H + +/* #define IP_NF_RTSP_DEBUG */ +#define IP_NF_RTSP_VERSION "0.01" + +/* port block types */ +typedef enum { + pb_single, /* client_port=x */ + pb_range, /* client_port=x-y */ + pb_discon /* client_port=x/y (rtspbis) */ +} portblock_t; + +/* We record seq number and length of rtsp headers here, all in host order. */ + +/* + * This structure is per expected connection. It is a member of struct + * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored + * there and we are expected to only store the length of the data which + * needs replaced. If a packet contains multiple RTSP messages, we create + * one expected connection per message. + * + * We use these variables to mark the entire header block. This may seem + * like overkill, but the nature of RTSP requires it. A header may appear + * multiple times in a message. We must treat two Transport headers the + * same as one Transport header with two entries. + */ +struct ip_ct_rtsp_expect +{ + u_int32_t len; /* length of header block */ + portblock_t pbtype; /* Type of port block that was requested */ + u_int16_t loport; /* Port that was requested, low or first */ + u_int16_t hiport; /* Port that was requested, high or second */ +#if 0 + uint method; /* RTSP method */ + uint cseq; /* CSeq from request */ +#endif +}; + +/* This structure exists only once per master */ +struct ip_ct_rtsp_master +{ + /* Empty (?) */ +}; + + +#ifdef __KERNEL__ + +#include + +#define RTSP_PORT 554 + +/* Protects rtsp part of conntracks */ +DECLARE_LOCK_EXTERN(ip_rtsp_lock); + +#endif /* __KERNEL__ */ + +#endif /* _IP_CONNTRACK_RTSP_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_talk.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_talk.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_talk.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_talk.h 2003-12-10 23:14:15.479601440 +0100 @@ -0,0 +1,152 @@ +#ifndef _IP_CONNTRACK_TALK_H +#define _IP_CONNTRACK_TALK_H +/* TALK tracking. */ + +#ifdef __KERNEL__ +#include +#include + +/* Protects talk part of conntracks */ +DECLARE_LOCK_EXTERN(ip_talk_lock); +#endif + + +#define TALK_PORT 517 +#define NTALK_PORT 518 + +/* talk structures and constants from */ + +/* + * 4.3BSD struct sockaddr + */ +struct talk_addr { + u_int16_t ta_family; + u_int16_t ta_port; + u_int32_t ta_addr; + u_int32_t ta_junk1; + u_int32_t ta_junk2; +}; + +#define TALK_OLD_NSIZE 9 +#define TALK_NSIZE 12 +#define TALK_TTY_NSIZE 16 + +/* + * Client->server request message formats. + */ +struct talk_msg { + u_char type; /* request type, see below */ + char l_name[TALK_OLD_NSIZE];/* caller's name */ + char r_name[TALK_OLD_NSIZE];/* callee's name */ + u_char pad; + u_int32_t id_num; /* message id */ + int32_t pid; /* caller's process id */ + char r_tty[TALK_TTY_NSIZE];/* callee's tty name */ + struct talk_addr addr; /* old (4.3) style */ + struct talk_addr ctl_addr; /* old (4.3) style */ +}; + +struct ntalk_msg { + u_char vers; /* protocol version */ + u_char type; /* request type, see below */ + u_char answer; /* not used */ + u_char pad; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* old (4.3) style */ + struct talk_addr ctl_addr; /* old (4.3) style */ + int32_t pid; /* caller's process id */ + char l_name[TALK_NSIZE];/* caller's name */ + char r_name[TALK_NSIZE];/* callee's name */ + char r_tty[TALK_TTY_NSIZE];/* callee's tty name */ +}; + +struct ntalk2_msg { + u_char vers; /* talk protocol version */ + u_char type; /* request type */ + u_char answer; /* */ + u_char extended; /* !0 if additional parts */ + u_int32_t id_num; /* message id number (dels) */ + struct talk_addr addr; /* target address */ + struct talk_addr ctl_addr; /* reply to address */ + int32_t pid; /* caller's process id */ + char l_name[TALK_NSIZE]; /* caller's name */ + char r_name[TALK_NSIZE]; /* callee's name */ + char r_tty[TALK_TTY_NSIZE]; /* callee's tty */ +}; + +/* + * Server->client response message formats. + */ +struct talk_response { + u_char type; /* type of request message, see below */ + u_char answer; /* response to request message, see below */ + u_char pad[2]; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* address for establishing conversation */ +}; + +struct ntalk_response { + u_char vers; /* protocol version */ + u_char type; /* type of request message, see below */ + u_char answer; /* response to request message, see below */ + u_char pad; + u_int32_t id_num; /* message id */ + struct talk_addr addr; /* address for establishing conversation */ +}; + +struct ntalk2_response { + u_char vers; /* protocol version */ + u_char type; /* type of request message */ + u_char answer; /* response to request */ + u_char rvers; /* Version of answering vers*/ + u_int32_t id_num; /* message id number */ + struct talk_addr addr; /* address for connection */ + /* This is at the end to compatiblize this with NTALK version. */ + char r_name[TALK_NSIZE]; /* callee's name */ +}; + +#define TALK_STR(data, talk_str, member) ((struct talk_str *)data)->member) +#define TALK_RESP(data, ver, member) (ver ? ((struct ntalk_response *)data)->member : ((struct talk_response *)data)->member) +#define TALK_MSG(data, ver, member) (ver ? ((struct ntalk_msg *)data)->member : ((struct talk_msg *)data)->member) + +#define TALK_VERSION 0 /* protocol versions */ +#define NTALK_VERSION 1 +#define NTALK2_VERSION 2 + +/* message type values */ +#define LEAVE_INVITE 0 /* leave invitation with server */ +#define LOOK_UP 1 /* check for invitation by callee */ +#define DELETE 2 /* delete invitation by caller */ +#define ANNOUNCE 3 /* announce invitation by caller */ +/* NTALK2 */ +#define REPLY_QUERY 4 /* request reply data from local daemon */ + +/* answer values */ +#define SUCCESS 0 /* operation completed properly */ +#define NOT_HERE 1 /* callee not logged in */ +#define FAILED 2 /* operation failed for unexplained reason */ +#define MACHINE_UNKNOWN 3 /* caller's machine name unknown */ +#define PERMISSION_DENIED 4 /* callee's tty doesn't permit announce */ +#define UNKNOWN_REQUEST 5 /* request has invalid type value */ +#define BADVERSION 6 /* request has invalid protocol version */ +#define BADADDR 7 /* request has invalid addr value */ +#define BADCTLADDR 8 /* request has invalid ctl_addr value */ +/* NTALK2 */ +#define NO_CALLER 9 /* no-one calling answer from REPLY */ +#define TRY_HERE 10 /* Not on this machine, try this */ +#define SELECTIVE_REFUSAL 11 /* User Filter refusal. */ +#define MAX_RESPONSE_TYPE 11 /* Make sure this is updated */ + +/* We don't really need much for talk */ +struct ip_ct_talk_expect +{ + /* Port that was to be used */ + u_int16_t port; +}; + +/* This structure exists only once per master */ +struct ip_ct_talk_master +{ +}; + +#endif /* _IP_CONNTRACK_TALK_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_tuple.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-11-26 21:44:58.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-12-10 23:13:04.122449376 +0100 @@ -14,7 +14,7 @@ union ip_conntrack_manip_proto { /* Add other protocols here. */ - u_int16_t all; + u_int32_t all; struct { u_int16_t port; @@ -25,6 +25,9 @@ struct { u_int16_t id; } icmp; + struct { + u_int32_t key; + } gre; }; /* The manipulable part of the tuple. */ @@ -44,7 +47,7 @@ u_int32_t ip; union { /* Add other protocols here. */ - u_int16_t all; + u_int64_t all; struct { u_int16_t port; @@ -55,6 +58,11 @@ struct { u_int8_t type, code; } icmp; + struct { + u_int16_t protocol; + u_int8_t version; + u_int32_t key; + } gre; } u; /* The protocol. */ @@ -80,10 +88,16 @@ #ifdef __KERNEL__ #define DUMP_TUPLE(tp) \ -DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ +DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \ (tp), (tp)->dst.protonum, \ - NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ - NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) + NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \ + NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all)) + +#define DUMP_TUPLE_RAW(x) \ + DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\ + (x), (x)->dst.protonum, \ + NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \ + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all)) #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_nat_pptp.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_nat_pptp.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_nat_pptp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_nat_pptp.h 2003-11-17 09:09:34.000000000 +0100 @@ -0,0 +1,11 @@ +/* PPTP constants and structs */ +#ifndef _NAT_PPTP_H +#define _NAT_PPTP_H + +/* conntrack private data */ +struct ip_nat_pptp { + u_int16_t pns_call_id; /* NAT'ed PNS call id */ + u_int16_t pac_call_id; /* NAT'ed PAC call id */ +}; + +#endif /* _NAT_PPTP_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_pool.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_pool.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_pool.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_pool.h 2003-12-10 23:13:39.981997896 +0100 @@ -0,0 +1,64 @@ +#ifndef _IP_POOL_H +#define _IP_POOL_H + +/***************************************************************************/ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation; either version 2 of the License, or */ +/* (at your option) any later version. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/ +/***************************************************************************/ + +/* A sockopt of such quality has hardly ever been seen before on the open + * market! This little beauty, hardly ever used: above 64, so it's + * traditionally used for firewalling, not touched (even once!) by the + * 2.0, 2.2 and 2.4 kernels! + * + * Comes with its own certificate of authenticity, valid anywhere in the + * Free world! + * + * Rusty, 19.4.2000 + */ +#define SO_IP_POOL 81 + +typedef int ip_pool_t; /* pool index */ +#define IP_POOL_NONE ((ip_pool_t)-1) + +struct ip_pool_request { + int op; + ip_pool_t index; + u_int32_t addr; + u_int32_t addr2; +}; + +/* NOTE: I deliberately break the first cut ippool utility. Nobody uses it. */ + +#define IP_POOL_BAD001 0x00000010 + +#define IP_POOL_FLUSH 0x00000011 /* req.index, no arguments */ +#define IP_POOL_INIT 0x00000012 /* from addr to addr2 incl. */ +#define IP_POOL_DESTROY 0x00000013 /* req.index, no arguments */ +#define IP_POOL_ADD_ADDR 0x00000014 /* add addr to pool */ +#define IP_POOL_DEL_ADDR 0x00000015 /* del addr from pool */ +#define IP_POOL_HIGH_NR 0x00000016 /* result in req.index */ +#define IP_POOL_LOOKUP 0x00000017 /* result in addr and addr2 */ +#define IP_POOL_USAGE 0x00000018 /* result in addr */ +#define IP_POOL_TEST_ADDR 0x00000019 /* result (0/1) returned */ + +#ifdef __KERNEL__ + +/* NOTE: ip_pool_match() and ip_pool_mod() expect ADDR to be host byte order */ +extern int ip_pool_match(ip_pool_t pool, u_int32_t addr); +extern int ip_pool_mod(ip_pool_t pool, u_int32_t addr, int isdel); + +#endif + +#endif /*_IP_POOL_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_queue.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_queue.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_queue.h 2003-11-26 21:45:32.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_queue.h 2003-12-10 23:14:19.439999368 +0100 @@ -47,10 +47,20 @@ unsigned char payload[0]; /* Optional replacement packet */ } ipq_verdict_msg_t; +typedef struct ipq_vwmark_msg { + unsigned int value; /* Verdict to hand to netfilter */ + unsigned long id; /* Packet ID for this verdict */ + size_t data_len; /* Length of replacement data */ + unsigned char payload[0]; /* Optional replacement packet */ + unsigned long nfmark; /* Mark for the Packet */ +} ipq_vwmark_msg_t; + + typedef struct ipq_peer_msg { union { ipq_verdict_msg_t verdict; ipq_mode_msg_t mode; + ipq_vwmark_msg_t vwmark; } msg; } ipq_peer_msg_t; @@ -67,6 +77,7 @@ #define IPQM_MODE (IPQM_BASE + 1) /* Mode request from peer */ #define IPQM_VERDICT (IPQM_BASE + 2) /* Verdict from peer */ #define IPQM_PACKET (IPQM_BASE + 3) /* Packet from kernel */ -#define IPQM_MAX (IPQM_BASE + 4) +#define IPQM_VWMARK (IPQM_BASE + 4) /* Verdict and mark from peer */ +#define IPQM_MAX (IPQM_BASE + 5) #endif /*_IP_QUEUE_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_tables.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_tables.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ip_tables.h 2003-11-26 21:44:17.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ip_tables.h 2003-12-10 23:13:24.656327752 +0100 @@ -134,6 +134,12 @@ /* Back pointer */ unsigned int comefrom; + /* Name of the chain */ + char *chainname; + + /* Rule number in the chain. */ + u_int32_t rulenum; + /* Packet and byte counters. */ struct ipt_counters counters; diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_addrtype.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_addrtype.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_addrtype.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_addrtype.h 2003-12-10 23:13:51.091309024 +0100 @@ -0,0 +1,11 @@ +#ifndef _IPT_ADDRTYPE_H +#define _IPT_ADDRTYPE_H + +struct ipt_addrtype_info { + u_int16_t source; /* source-type mask */ + u_int16_t dest; /* dest-type mask */ + int invert_source; + int invert_dest; +}; + +#endif diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_condition.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_condition.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_condition.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_condition.h 2003-12-10 23:13:53.355964744 +0100 @@ -0,0 +1,11 @@ +#ifndef __IPT_CONDITION_MATCH__ +#define __IPT_CONDITION_MATCH__ + +#define CONDITION_NAME_LEN 32 + +struct condition_info { + char name[CONDITION_NAME_LEN]; + int invert; +}; + +#endif diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_connlimit.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_connlimit.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_connlimit.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_connlimit.h 2003-12-10 23:13:26.810000344 +0100 @@ -0,0 +1,12 @@ +#ifndef _IPT_CONNLIMIT_H +#define _IPT_CONNLIMIT_H + +struct ipt_connlimit_data; + +struct ipt_connlimit_info { + int limit; + int inverse; + u_int32_t mask; + struct ipt_connlimit_data *data; +}; +#endif /* _IPT_CONNLIMIT_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_connmark.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_connmark.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_connmark.h 2003-12-10 23:13:54.582778240 +0100 @@ -0,0 +1,9 @@ +#ifndef _IPT_CONNMARK_H +#define _IPT_CONNMARK_H + +struct ipt_connmark_info { + unsigned long mark, mask; + u_int8_t invert; +}; + +#endif /*_IPT_CONNMARK_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_CONNMARK.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_CONNMARK.h 2003-12-10 23:13:54.582778240 +0100 @@ -0,0 +1,15 @@ +#ifndef _IPT_CONNMARK_H_target +#define _IPT_CONNMARK_H_target + +enum { + IPT_CONNMARK_SET = 0, + IPT_CONNMARK_SAVE, + IPT_CONNMARK_RESTORE +}; + +struct ipt_connmark_target_info { + unsigned long mark; + u_int8_t mode; +}; + +#endif /*_IPT_CONNMARK_H_target*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_conntrack.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_conntrack.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_conntrack.h 2003-11-26 21:45:07.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_conntrack.h 2003-12-10 23:13:24.657327600 +0100 @@ -10,6 +10,7 @@ #define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1)) #define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2)) +#define IPT_CONNTRACK_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 3)) /* flags, invflags: */ #define IPT_CONNTRACK_STATE 0x01 diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_dstlimit.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_dstlimit.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_dstlimit.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_dstlimit.h 2003-12-10 23:13:27.868839376 +0100 @@ -0,0 +1,36 @@ +#ifndef _IPT_DSTLIMIT_H +#define _IPT_DSTLIMIT_H + +/* timings are in milliseconds. */ +#define IPT_DSTLIMIT_SCALE 10000 +/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 + seconds, or one every 59 hours. */ + +/* details of this structure hidden by the implementation */ +struct ipt_dstlimit_htable; + +#define IPT_DSTLIMIT_HASH_DIP 0x0001 +#define IPT_DSTLIMIT_HASH_DPT 0x0002 +#define IPT_DSTLIMIT_HASH_SIP 0x0004 + +struct ipt_dstlimit_info { + u_int32_t mode; /* bitmask of IPT_DSTLIMIT_HASH_* */ + u_int32_t avg; /* Average secs between packets * scale */ + u_int32_t burst; /* Period multiplier for upper limit. */ + + /* user specified */ + unsigned int size; /* how many buckets */ + unsigned int max; /* max number of entries */ + unsigned int gc_interval; /* gc interval */ + unsigned int expire; /* when do entries expire? */ + char name [IFNAMSIZ]; /* name */ + + struct ipt_dstlimit_htable *hinfo; + + /* Used internally by the kernel */ + union { + void *ptr; + struct ipt_dstlimit_info *master; + } u; +}; +#endif /*_IPT_DSTLIMIT_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_fuzzy.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_fuzzy.h 2003-12-10 23:13:30.016512880 +0100 @@ -0,0 +1,21 @@ +#ifndef _IPT_FUZZY_H +#define _IPT_FUZZY_H + +#include +#include + +#define MAXFUZZYRATE 10000000 +#define MINFUZZYRATE 3 + +struct ipt_fuzzy_info { + u_int32_t minimum_rate; + u_int32_t maximum_rate; + u_int32_t packets_total; + u_int32_t bytes_total; + u_int32_t previous_time; + u_int32_t present_time; + u_int32_t mean_rate; + u_int8_t acceptance_rate; +}; + +#endif /*_IPT_FUZZY_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_IPMARK.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_IPMARK.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_IPMARK.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_IPMARK.h 2003-12-10 23:13:59.369050616 +0100 @@ -0,0 +1,13 @@ +#ifndef _IPT_IPMARK_H_target +#define _IPT_IPMARK_H_target + +struct ipt_ipmark_target_info { + unsigned long andmask; + unsigned long ormask; + unsigned int addr; +}; + +#define IPT_IPMARK_SRC 0 +#define IPT_IPMARK_DST 1 + +#endif /*_IPT_IPMARK_H_target*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ipv4options.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ipv4options.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ipv4options.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ipv4options.h 2003-12-10 23:13:32.270170272 +0100 @@ -0,0 +1,21 @@ +#ifndef __ipt_ipv4options_h_included__ +#define __ipt_ipv4options_h_included__ + +#define IPT_IPV4OPTION_MATCH_SSRR 0x01 /* For strict source routing */ +#define IPT_IPV4OPTION_MATCH_LSRR 0x02 /* For loose source routing */ +#define IPT_IPV4OPTION_DONT_MATCH_SRR 0x04 /* any source routing */ +#define IPT_IPV4OPTION_MATCH_RR 0x08 /* For Record route */ +#define IPT_IPV4OPTION_DONT_MATCH_RR 0x10 +#define IPT_IPV4OPTION_MATCH_TIMESTAMP 0x20 /* For timestamp request */ +#define IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP 0x40 +#define IPT_IPV4OPTION_MATCH_ROUTER_ALERT 0x80 /* For router-alert */ +#define IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT 0x100 +#define IPT_IPV4OPTION_MATCH_ANY_OPT 0x200 /* match packet with any option */ +#define IPT_IPV4OPTION_DONT_MATCH_ANY_OPT 0x400 /* match packet with no option */ + +struct ipt_ipv4options_info { + u_int16_t options; +}; + + +#endif /* __ipt_ipv4options_h_included__ */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_mark.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_mark.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_mark.h 2003-11-26 21:45:46.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_mark.h 2003-12-10 23:14:21.806639584 +0100 @@ -1,9 +1,16 @@ #ifndef _IPT_MARK_H #define _IPT_MARK_H +enum { + IPT_MARK_BIT_OP_NONE, + IPT_MARK_BIT_OP_AND, + IPT_MARK_BIT_OP_OR +}; + struct ipt_mark_info { unsigned long mark, mask; u_int8_t invert; + u_int8_t bit_op; }; #endif /*_IPT_MARK_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_mport.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_mport.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_mport.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_mport.h 2003-12-10 23:13:34.440840280 +0100 @@ -0,0 +1,24 @@ +#ifndef _IPT_MPORT_H +#define _IPT_MPORT_H +#include + +#define IPT_MPORT_SOURCE (1<<0) +#define IPT_MPORT_DESTINATION (1<<1) +#define IPT_MPORT_EITHER (IPT_MPORT_SOURCE|IPT_MPORT_DESTINATION) + +#define IPT_MULTI_PORTS 15 + +/* Must fit inside union ipt_matchinfo: 32 bytes */ +/* every entry in ports[] except for the last one has one bit in pflags + * associated with it. If this bit is set, the port is the first port of + * a portrange, with the next entry being the last. + * End of list is marked with pflags bit set and port=65535. + * If 14 ports are used (last one does not have a pflag), the last port + * is repeated to fill the last entry in ports[] */ +struct ipt_mport +{ + u_int8_t flags:2; /* Type of comparison */ + u_int16_t pflags:14; /* Port flags */ + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ +}; +#endif /*_IPT_MPORT_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_NETLINK.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_NETLINK.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_NETLINK.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_NETLINK.h 2003-12-10 23:13:35.507678096 +0100 @@ -0,0 +1,27 @@ +#ifndef _IPT_FWMON_H +#define _IPT_FWMON_H + +/* Bitmask macros */ +#define MASK(x,y) (x & y) +#define MASK_SET(x,y) x |= y +#define MASK_UNSET(x,y) x &= ~y + +#define USE_MARK 0x00000001 +#define USE_DROP 0x00000002 +#define USE_SIZE 0x00000004 + +struct ipt_nldata +{ + unsigned int flags; + unsigned int mark; + unsigned int size; +}; + +/* Old header */ +struct netlink_t { + unsigned int len; + unsigned int mark; + char iface[IFNAMSIZ]; +}; + +#endif /*_IPT_FWMON_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_nth.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_nth.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_nth.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_nth.h 2003-12-10 23:13:37.748337464 +0100 @@ -0,0 +1,19 @@ +#ifndef _IPT_NTH_H +#define _IPT_NTH_H + +#include +#include + +#ifndef IPT_NTH_NUM_COUNTERS +#define IPT_NTH_NUM_COUNTERS 16 +#endif + +struct ipt_nth_info { + u_int8_t every; + u_int8_t not; + u_int8_t startat; + u_int8_t counter; + u_int8_t packet; +}; + +#endif /*_IPT_NTH_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_osf.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_osf.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_osf.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_osf.h 2003-12-10 23:13:38.897162816 +0100 @@ -0,0 +1,121 @@ +/* + * ipt_osf.h + * + * Copyright (c) 2003 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _IPT_OSF_H +#define _IPT_OSF_H + +#define MAXGENRELEN 32 +#define MAXDETLEN 64 + +#include + +struct ipt_osf_info +{ + char genre[MAXGENRELEN]; + int len; + int invert; /* UNSUPPORTED */ +}; + +struct osf_wc +{ + char wc; + unsigned long val; +}; + +/* This struct represents IANA options + * http://www.iana.org/assignments/tcp-parameters + */ +struct osf_opt +{ + unsigned char kind; + unsigned char length; + struct osf_wc wc; +}; + +#ifdef __KERNEL__ + +struct osf_finger +{ + struct list_head flist; + struct osf_wc wss; + unsigned char ttl; + unsigned char df; + unsigned long ss; + char genre[MAXGENRELEN]; + char version[MAXGENRELEN], subtype[MAXGENRELEN]; + + /* Not needed, but for consistency with original table from Michal Zalewski */ + char details[MAXDETLEN]; + + int opt_num; + struct osf_opt opt[MAX_IPOPTLEN]; /* In case it is all NOP or EOL */ + +}; + +/* Defines for IANA option kinds */ + +#define OSFOPT_EOL 0 /* End of options */ +#define OSFOPT_NOP 1 /* NOP */ +#define OSFOPT_MSS 2 /* Maximum segment size */ +#define OSFOPT_WSO 3 /* Window scale option */ +#define OSFOPT_SACKP 4 /* SACK permitted */ +#define OSFOPT_SACK 5 /* SACK */ +#define OSFOPT_ECHO 6 +#define OSFOPT_ECHOREPLY 7 +#define OSFOPT_TS 8 /* Timestamp option */ +#define OSFOPT_POCP 9 /* Partial Order Connection Permitted */ +#define OSFOPT_POSP 10 /* Partial Order Service Profile */ +/* Others are not used in current OSF */ + +static struct osf_opt IANA_opts[] = +{ + {0, 1,}, + {1, 1,}, + {2, 4,}, + {3, 3,}, + {4, 2,}, + {5, 1 ,}, /* SACK length is not defined */ + {6, 6,}, + {7, 6,}, + {8, 10,}, + {9, 2,}, + {10, 3,}, + {11, 1,}, /* CC: Suppose 1 */ + {12, 1,}, /* the same */ + {13, 1,}, /* and here too */ + {14, 3,}, + {15, 1,}, /* TCP Alternate Checksum Data. Length is not defined */ + {16, 1,}, + {17, 1,}, + {18, 3,}, + {19, 18,}, + {20, 1,}, + {21, 1,}, + {22, 1,}, + {23, 1,}, + {24, 1,}, + {25, 1,}, + {26, 1,}, +}; + +#endif /* __KERNEL__ */ + +#endif /* _IPT_OSF_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_pool.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_pool.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_pool.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_pool.h 2003-12-10 23:13:39.981997896 +0100 @@ -0,0 +1,25 @@ +#ifndef _IPT_POOL_H +#define _IPT_POOL_H + +#include + +#define IPT_POOL_INV_SRC 0x00000001 +#define IPT_POOL_INV_DST 0x00000002 +#define IPT_POOL_DEL_SRC 0x00000004 +#define IPT_POOL_DEL_DST 0x00000008 +#define IPT_POOL_INV_MOD_SRC 0x00000010 +#define IPT_POOL_INV_MOD_DST 0x00000020 +#define IPT_POOL_MOD_SRC_ACCEPT 0x00000040 +#define IPT_POOL_MOD_DST_ACCEPT 0x00000080 +#define IPT_POOL_MOD_SRC_DROP 0x00000100 +#define IPT_POOL_MOD_DST_DROP 0x00000200 + +/* match info */ +struct ipt_pool_info +{ + ip_pool_t src; + ip_pool_t dst; + unsigned flags; +}; + +#endif /*_IPT_POOL_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_psd.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_psd.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_psd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_psd.h 2003-12-10 23:13:41.104827200 +0100 @@ -0,0 +1,40 @@ +#ifndef _IPT_PSD_H +#define _IPT_PSD_H + +#include +#include + +/* + * High port numbers have a lower weight to reduce the frequency of false + * positives, such as from passive mode FTP transfers. + */ +#define PORT_WEIGHT_PRIV 3 +#define PORT_WEIGHT_HIGH 1 + +/* + * Port scan detection thresholds: at least COUNT ports need to be scanned + * from the same source, with no longer than DELAY ticks between ports. + */ +#define SCAN_MIN_COUNT 7 +#define SCAN_MAX_COUNT (SCAN_MIN_COUNT * PORT_WEIGHT_PRIV) +#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT +#define SCAN_DELAY_THRESHOLD (HZ * 3) + +/* + * Keep track of up to LIST_SIZE source addresses, using a hash table of + * HASH_SIZE entries for faster lookups, but limiting hash collisions to + * HASH_MAX source addresses per the same hash value. + */ +#define LIST_SIZE 0x100 +#define HASH_LOG 9 +#define HASH_SIZE (1 << HASH_LOG) +#define HASH_MAX 0x10 + +struct ipt_psd_info { + unsigned int weight_threshold; + unsigned int delay_threshold; + unsigned short lo_ports_weight; + unsigned short hi_ports_weight; +}; + +#endif /*_IPT_PSD_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_quota.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_quota.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_quota.h 2003-12-10 23:13:42.203660152 +0100 @@ -0,0 +1,11 @@ +#ifndef _IPT_QUOTA_H +#define _IPT_QUOTA_H + +/* print debug info in both kernel/netfilter module & iptable library */ +//#define DEBUG_IPT_QUOTA + +struct ipt_quota_info { + u_int64_t quota; +}; + +#endif /*_IPT_QUOTA_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_random.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_random.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_random.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_random.h 2003-12-10 23:13:44.404325600 +0100 @@ -0,0 +1,11 @@ +#ifndef _IPT_RAND_H +#define _IPT_RAND_H + +#include +#include + +struct ipt_rand_info { + u_int8_t average; +}; + +#endif /*_IPT_RAND_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_realm.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_realm.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_realm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_realm.h 2003-12-10 23:13:45.528154752 +0100 @@ -0,0 +1,9 @@ +#ifndef _IPT_REALM_H +#define _IPT_REALM_H + +struct ipt_realm_info { + u_int32_t id; + u_int32_t mask; + u_int8_t invert; +}; +#endif /*_IPT_REALM_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_REJECT.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_REJECT.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_REJECT.h 2003-11-26 21:45:21.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_REJECT.h 2003-12-10 23:14:20.642816512 +0100 @@ -15,6 +15,7 @@ struct ipt_reject_info { enum ipt_reject_with with; /* reject type */ + u_int8_t fake_source_address; /* 1: fake src addr with original packet dest, 0: no fake */ }; -#endif /*_IPT_REJECT_H*/ +#endif /* _IPT_REJECT_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ROUTE.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ROUTE.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ROUTE.h 2003-12-10 23:14:07.501814248 +0100 @@ -0,0 +1,22 @@ +/* Header file for iptables ipt_ROUTE target + * + * (C) 2002 by Cédric de Launois + * + * This software is distributed under GNU GPL v2, 1991 + */ +#ifndef _IPT_ROUTE_H_target +#define _IPT_ROUTE_H_target + +#define IPT_ROUTE_IFNAMSIZ 16 + +struct ipt_route_target_info { + char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */ + char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */ + u_int32_t gw; /* IP address of gateway */ + u_int8_t flags; +}; + +/* Values for "flags" field */ +#define IPT_ROUTE_CONTINUE 0x01 + +#endif /*_IPT_ROUTE_H_target*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_rpc.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_rpc.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_rpc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_rpc.h 2003-12-10 23:14:10.155410840 +0100 @@ -0,0 +1,35 @@ +/* RPC extension for IP netfilter matching, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original rpc tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ipt_rpc.h.c,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + */ + +#ifndef _IPT_RPC_H +#define _IPT_RPC_H + +struct ipt_rpc_data; + +struct ipt_rpc_info { + int inverse; + int strict; + const char c_procs[1408]; + int i_procs; + struct ipt_rpc_data *data; +}; + +#endif /* _IPT_RPC_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_sctp.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_sctp.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_sctp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_sctp.h 2003-12-10 23:13:25.744162376 +0100 @@ -0,0 +1,25 @@ +/* iptables module for matching the SCTP header + * + * (C) 2003 Harald Welte + * + * This software is distributed under GNU GPL v2, 1991 + * + * $Id$ + */ +#ifndef _IPT_SCTP_H +#define _IPT_SCTP_H + +struct ipt_sctp_info { + u_int16_t spts[2]; /* Souce port range */ + u_int16_t dpts[2]; /* Destination port range */ + u_int32_t chunks; /* chunks to be matched */ + u_int32_t chunk_mask; /* chunk mask to be matched */ + u_int8_t invflags; /* Inverse flags */ +}; + +#define IPT_SCTP_INV_SRCPT 0x01 /* Invert the sense of source ports */ +#define IPT_SCTP_INV_DSTPT 0x02 /* Invert the sense of dest ports */ +#define IPT_SCTP_INV_CHUNKS 0x03 /* Invert the sense of chunks */ +#define IPT_SCTP_INV_MASK 0x03 /* All possible flags */ + +#endif /* _IPT_SCTP_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_state.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_state.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_state.h 2003-11-26 21:45:27.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_state.h 2003-12-10 23:13:24.657327600 +0100 @@ -4,6 +4,8 @@ #define IPT_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1)) #define IPT_STATE_INVALID (1 << 0) +#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1)) + struct ipt_state_info { unsigned int statemask; diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_string.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_string.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_string.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_string.h 2003-12-10 23:14:14.164801320 +0100 @@ -0,0 +1,21 @@ +#ifndef _IPT_STRING_H +#define _IPT_STRING_H + +/* *** PERFORMANCE TWEAK *** + * Packet size and search string threshold, + * above which sublinear searches is used. */ +#define IPT_STRING_HAYSTACK_THRESH 100 +#define IPT_STRING_NEEDLE_THRESH 20 + +#define BM_MAX_NLEN 256 +#define BM_MAX_HLEN 1024 + +typedef char *(*proc_ipt_search) (char *, char *, int, int); + +struct ipt_string_info { + char string[BM_MAX_NLEN]; + u_int16_t invert; + u_int16_t len; +}; + +#endif /* _IPT_STRING_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_TCPLAG.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_TCPLAG.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_TCPLAG.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_TCPLAG.h 2003-12-10 23:14:16.739409920 +0100 @@ -0,0 +1,10 @@ +#ifndef _IPT_TCPLAG_H +#define _IPT_TCPLAG_H + +struct ipt_tcplag +{ + unsigned char level; + unsigned char prefix[ 15 ]; +}; + +#endif diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_time.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_time.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_time.h 2003-12-10 23:13:47.814807128 +0100 @@ -0,0 +1,13 @@ +#ifndef __ipt_time_h_included__ +#define __ipt_time_h_included__ + + +struct ipt_time_info { + u_int8_t days_match; /* 1 bit per day. -SMTWTFS */ + u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */ + u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */ + u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */ +}; + + +#endif /* __ipt_time_h_included__ */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_TTL.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_TTL.h 2003-12-10 23:13:48.933637040 +0100 @@ -0,0 +1,21 @@ +/* TTL modification module for IP tables + * (C) 2000 by Harald Welte */ + +#ifndef _IPT_TTL_H +#define _IPT_TTL_H + +enum { + IPT_TTL_SET = 0, + IPT_TTL_INC, + IPT_TTL_DEC +}; + +#define IPT_TTL_MAXMODE IPT_TTL_DEC + +struct ipt_TTL_info { + u_int8_t mode; + u_int8_t ttl; +}; + + +#endif diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_u32.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_u32.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_u32.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_u32.h 2003-12-10 23:13:50.005474096 +0100 @@ -0,0 +1,40 @@ +#ifndef _IPT_U32_H +#define _IPT_U32_H +#include + +enum ipt_u32_ops +{ + IPT_U32_AND, + IPT_U32_LEFTSH, + IPT_U32_RIGHTSH, + IPT_U32_AT +}; + +struct ipt_u32_location_element +{ + u_int32_t number; + u_int8_t nextop; +}; +struct ipt_u32_value_element +{ + u_int32_t min; + u_int32_t max; +}; +/* *** any way to allow for an arbitrary number of elements? + for now I settle for a limit of 10 of each */ +#define U32MAXSIZE 10 +struct ipt_u32_test +{ + u_int8_t nnums; + struct ipt_u32_location_element location[U32MAXSIZE+1]; + u_int8_t nvalues; + struct ipt_u32_value_element value[U32MAXSIZE+1]; +}; + +struct ipt_u32 +{ + u_int8_t ntests; + struct ipt_u32_test tests[U32MAXSIZE+1]; +}; + +#endif /*_IPT_U32_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ULOG.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ULOG.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_ULOG.h 2003-11-26 21:43:39.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_ULOG.h 2003-12-10 23:13:22.344679176 +0100 @@ -11,6 +11,9 @@ #define NETLINK_NFLOG 5 #endif +#define NFLOG_DEFAULT_NLGROUP 1 +#define NFLOG_DEFAULT_QTHRESHOLD 1 + #define ULOG_MAC_LEN 80 #define ULOG_PREFIX_LEN 32 diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_XOR.h linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_XOR.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4/ipt_XOR.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4/ipt_XOR.h 2003-12-10 23:14:18.223184352 +0100 @@ -0,0 +1,9 @@ +#ifndef _IPT_XOR_H +#define _IPT_XOR_H + +struct ipt_XOR_info { + char key[30]; + u_int8_t block_size; +}; + +#endif /* _IPT_XOR_H */ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv4.h linux-2.6.0-test11/include/linux/netfilter_ipv4.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv4.h 2003-11-26 21:45:25.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv4.h 2003-12-10 23:13:24.657327600 +0100 @@ -51,6 +51,8 @@ enum nf_ip_hook_priorities { NF_IP_PRI_FIRST = INT_MIN, + NF_IP_PRI_CONNTRACK_DEFRAG = -400, + NF_IP_PRI_RAW = -300, NF_IP_PRI_CONNTRACK = -200, NF_IP_PRI_BRIDGE_SABOTAGE_FORWARD = -175, NF_IP_PRI_MANGLE = -150, diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6_tables.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6_tables.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6_tables.h 2003-11-26 21:45:41.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6_tables.h 2003-12-10 23:13:24.657327600 +0100 @@ -140,6 +140,12 @@ /* Back pointer */ unsigned int comefrom; + /* Name of the chain */ + char *chainname; + + /* Rule number in the chain. */ + u_int32_t rulenum; + /* Packet and byte counters. */ struct ip6t_counters counters; diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_condition.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_condition.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_condition.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_condition.h 2003-12-10 23:13:52.255132096 +0100 @@ -0,0 +1,11 @@ +#ifndef __IP6T_CONDITION_MATCH__ +#define __IP6T_CONDITION_MATCH__ + +#define CONDITION6_NAME_LEN 32 + +struct condition6_info { + char name[CONDITION6_NAME_LEN]; + int invert; +}; + +#endif diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_fuzzy.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2003-12-10 23:13:28.962673088 +0100 @@ -0,0 +1,21 @@ +#ifndef _IP6T_FUZZY_H +#define _IP6T_FUZZY_H + +#include +#include + +#define MAXFUZZYRATE 10000000 +#define MINFUZZYRATE 3 + +struct ip6t_fuzzy_info { + u_int32_t minimum_rate; + u_int32_t maximum_rate; + u_int32_t packets_total; + u_int32_t bytes_total; + u_int32_t previous_time; + u_int32_t present_time; + u_int32_t mean_rate; + u_int8_t acceptance_rate; +}; + +#endif /*_IP6T_FUZZY_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_HL.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_HL.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_HL.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_HL.h 2003-12-10 23:13:31.107347048 +0100 @@ -0,0 +1,22 @@ +/* Hop Limit modification module for ip6tables + * Maciej Soltysiak + * Based on HW's TTL module */ + +#ifndef _IP6T_HL_H +#define _IP6T_HL_H + +enum { + IP6T_HL_SET = 0, + IP6T_HL_INC, + IP6T_HL_DEC +}; + +#define IP6T_HL_MAXMODE IP6T_HL_DEC + +struct ip6t_HL_info { + u_int8_t mode; + u_int8_t hop_limit; +}; + + +#endif diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_nth.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_nth.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_nth.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_nth.h 2003-12-10 23:13:36.622508616 +0100 @@ -0,0 +1,19 @@ +#ifndef _IP6T_NTH_H +#define _IP6T_NTH_H + +#include +#include + +#ifndef IP6T_NTH_NUM_COUNTERS +#define IP6T_NTH_NUM_COUNTERS 16 +#endif + +struct ip6t_nth_info { + u_int8_t every; + u_int8_t not; + u_int8_t startat; + u_int8_t counter; + u_int8_t packet; +}; + +#endif /*_IP6T_NTH_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_owner.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_owner.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_owner.h 2003-11-26 21:44:32.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_owner.h 2003-12-10 23:14:05.028190296 +0100 @@ -6,12 +6,14 @@ #define IP6T_OWNER_GID 0x02 #define IP6T_OWNER_PID 0x04 #define IP6T_OWNER_SID 0x08 +#define IP6T_OWNER_COMM 0x10 struct ip6t_owner_info { uid_t uid; gid_t gid; pid_t pid; pid_t sid; + char comm[16]; u_int8_t match, invert; /* flags */ }; diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_random.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_random.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_random.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_random.h 2003-12-10 23:13:43.304492800 +0100 @@ -0,0 +1,11 @@ +#ifndef _IP6T_RAND_H +#define _IP6T_RAND_H + +#include +#include + +struct ip6t_rand_info { + u_int8_t average; +}; + +#endif /*_IP6T_RAND_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_REJECT.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_REJECT.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_REJECT.h 2003-11-26 21:42:47.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_REJECT.h 2003-12-10 23:13:46.679979648 +0100 @@ -2,15 +2,17 @@ #define _IP6T_REJECT_H enum ip6t_reject_with { - IP6T_ICMP_NET_UNREACHABLE, - IP6T_ICMP_HOST_UNREACHABLE, - IP6T_ICMP_PROT_UNREACHABLE, - IP6T_ICMP_PORT_UNREACHABLE, - IP6T_ICMP_ECHOREPLY + IP6T_ICMP6_NO_ROUTE, + IP6T_ICMP6_ADM_PROHIBITED, + IP6T_ICMP6_NOT_NEIGHBOUR, + IP6T_ICMP6_ADDR_UNREACH, + IP6T_ICMP6_PORT_UNREACH, + IP6T_ICMP6_ECHOREPLY, + IP6T_TCP_RESET }; struct ip6t_reject_info { enum ip6t_reject_with with; /* reject type */ }; -#endif /*_IPT_REJECT_H*/ +#endif /*_IP6T_REJECT_H*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_ROUTE.h --- linux-2.6.0-test11.org/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_ipv6/ip6t_ROUTE.h 2003-12-10 23:14:08.745625160 +0100 @@ -0,0 +1,22 @@ +/* Header file for iptables ip6t_ROUTE target + * + * (C) 2003 by Cédric de Launois + * + * This software is distributed under GNU GPL v2, 1991 + */ +#ifndef _IPT_ROUTE_H_target +#define _IPT_ROUTE_H_target + +#define IP6T_ROUTE_IFNAMSIZ 16 + +struct ip6t_route_target_info { + char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */ + char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */ + u_int32_t gw[4]; /* IPv6 address of gateway */ + u_int8_t flags; +}; + +/* Values for "flags" field */ +#define IP6T_ROUTE_CONTINUE 0x01 + +#endif /*_IP6T_ROUTE_H_target*/ diff -Nur linux-2.6.0-test11.org/include/linux/netfilter_mime.h linux-2.6.0-test11/include/linux/netfilter_mime.h --- linux-2.6.0-test11.org/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/include/linux/netfilter_mime.h 2003-12-10 23:14:12.890994968 +0100 @@ -0,0 +1,89 @@ +/* + * MIME functions for netfilter modules. This file provides implementations + * for basic MIME parsing. MIME headers are used in many protocols, such as + * HTTP, RTSP, SIP, etc. + * + * gcc will warn for defined but unused functions, so we only include the + * functions requested. The following macros are used: + * NF_NEED_MIME_NEXTLINE nf_mime_nextline() + */ +#ifndef _NETFILTER_MIME_H +#define _NETFILTER_MIME_H + +/* Only include these functions for kernel code. */ +#ifdef __KERNEL__ + +#include + +/* + * Given a buffer and length, advance to the next line and mark the current + * line. If the current line is empty, *plinelen will be set to zero. If + * not, it will be set to the actual line length (including CRLF). + * + * 'line' in this context means logical line (includes LWS continuations). + * Returns 1 on success, 0 on failure. + */ +#ifdef NF_NEED_MIME_NEXTLINE +static int +nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) +{ + uint off = *poff; + uint physlen = 0; + int is_first_line = 1; + + if (off >= len) + { + return 0; + } + + do + { + while (p[off] != '\n') + { + if (len-off <= 1) + { + return 0; + } + + physlen++; + off++; + } + + /* if we saw a crlf, physlen needs adjusted */ + if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') + { + physlen--; + } + + /* advance past the newline */ + off++; + + /* check for an empty line */ + if (physlen == 0) + { + break; + } + + /* check for colon on the first physical line */ + if (is_first_line) + { + is_first_line = 0; + if (memchr(p+(*poff), ':', physlen) == NULL) + { + return 0; + } + } + } + while (p[off] == ' ' || p[off] == '\t'); + + *plineoff = *poff; + *plinelen = (physlen == 0) ? 0 : (off - *poff); + *poff = off; + + return 1; +} +#endif /* NF_NEED_MIME_NEXTLINE */ + +#endif /* __KERNEL__ */ + +#endif /* _NETFILTER_MIME_H */ diff -Nur linux-2.6.0-test11.org/net/core/netfilter.c linux-2.6.0-test11/net/core/netfilter.c --- linux-2.6.0-test11.org/net/core/netfilter.c 2003-11-26 21:43:56.000000000 +0100 +++ linux-2.6.0-test11/net/core/netfilter.c 2003-12-10 23:14:03.998346856 +0100 @@ -8,8 +8,10 @@ * * February 2000: Modified by James Morris to have 1 queue per protocol. * 15-Mar-2000: Added NF_REPEAT --RR. + * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik. */ #include +#include #include #include #include @@ -61,6 +63,10 @@ } queue_handler[NPROTO]; static rwlock_t queue_handler_lock = RW_LOCK_UNLOCKED; +/** + * nf_register_hook - Register with a netfilter hook + * @reg: Hook operations to be registered + */ int nf_register_hook(struct nf_hook_ops *reg) { struct list_head *i; @@ -77,6 +83,10 @@ return 0; } +/** + * nf_unregister_hook - Unregister from a netfilter hook + * @reg: hook operations to be unregistered + */ void nf_unregister_hook(struct nf_hook_ops *reg) { spin_lock_bh(&nf_hook_lock); @@ -389,6 +399,18 @@ return NF_ACCEPT; } +/** + * nf_register_queue_handler - Registere a queue handler with netfilter + * @pf: protocol family + * @outfn: function called by core to enqueue a packet + * @data: opaque parameter, passed through + * + * This function registers a queue handler with netfilter. There can only + * be one queue handler for every protocol family. + * + * A queue handler _must_ reinject every packet via nf_reinject, no + * matter what. + */ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) { int ret; @@ -406,7 +428,12 @@ return ret; } -/* The caller must flush their queue before this */ +/** + * nf_unregister_queue_handler - Unregister queue handler from netfilter + * @pf: protocol family + * + * The caller must flush their queue before unregistering + */ int nf_unregister_queue_handler(int pf) { write_lock_bh(&queue_handler_lock); @@ -549,6 +576,15 @@ return ret; } +/** + * nf_reinject - Reinject a packet from a queue handler + * @skb: the packet to be reinjected + * @info: info which was passed to the outfn() of the queue handler + * @verdict: verdict (NF_ACCEPT, ...) for this packet + * + * This is the function called by a queue handler to reinject a + * packet. + */ void nf_reinject(struct sk_buff *skb, struct nf_info *info, unsigned int verdict) { @@ -743,7 +779,70 @@ EXPORT_SYMBOL(skb_ip_make_writable); #endif /*CONFIG_INET*/ +/* Internal logging interface, which relies on the real + LOG target modules */ + +#define NF_LOG_PREFIXLEN 128 + +static nf_logfn *nf_logging[NPROTO]; /* = NULL */ +static int reported = 0; +static spinlock_t nf_log_lock = SPIN_LOCK_UNLOCKED; + +int nf_log_register(int pf, nf_logfn *logfn) +{ + int ret = -EBUSY; + + /* Any setup of logging members must be done before + * substituting pointer. */ + smp_wmb(); + spin_lock(&nf_log_lock); + if (!nf_logging[pf]) { + nf_logging[pf] = logfn; + ret = 0; + } + spin_unlock(&nf_log_lock); + return ret; +} +void nf_log_unregister(int pf, nf_logfn *logfn) +{ + spin_lock(&nf_log_lock); + if (nf_logging[pf] == logfn) + nf_logging[pf] = NULL; + spin_unlock(&nf_log_lock); + + /* Give time to concurrent readers. */ + synchronize_net(); +} + +void nf_log_packet(int pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const char *fmt, ...) +{ + va_list args; + char prefix[NF_LOG_PREFIXLEN]; + nf_logfn *logfn; + + rcu_read_lock(); + logfn = nf_logging[pf]; + if (logfn) { + va_start(args, fmt); + vsnprintf(prefix, sizeof(prefix), fmt, args); + va_end(args); + /* We must read logging before nf_logfn[pf] */ + smp_read_barrier_depends(); + logfn(hooknum, skb, in, out, prefix); + } else if (!reported) { + printk(KERN_WARNING "nf_log_packet: can\'t log yet, " + "no backend logging module loaded in!\n"); + reported++; + } + rcu_read_unlock(); +} + /* This does not belong here, but ipt_REJECT needs it if connection tracking in use: without this, connection may not be in hash table, and hence manufactured ICMP or RST packets will not be associated @@ -763,6 +862,9 @@ EXPORT_SYMBOL(ip_ct_attach); EXPORT_SYMBOL(ip_route_me_harder); EXPORT_SYMBOL(nf_getsockopt); +EXPORT_SYMBOL(nf_log_register); +EXPORT_SYMBOL(nf_log_unregister); +EXPORT_SYMBOL(nf_log_packet); EXPORT_SYMBOL(nf_hook_slow); EXPORT_SYMBOL(nf_hooks); EXPORT_SYMBOL(nf_register_hook); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_core.c 2003-11-26 21:42:40.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_core.c 2003-12-10 23:14:22.975461896 +0100 @@ -4,6 +4,7 @@ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General * Public Licence. + * (C) 2000-2003 by the netfilter core team * * 23 Apr 2001: Harald Welte * - new API and handling of conntrack/nat helpers @@ -11,6 +12,8 @@ * 16 Jul 2002: Harald Welte * - add usage/reference counts to ip_conntrack_expect * - export ip_conntrack[_expect]_{find_get,put} functions + * 05 Aug 2002: Harald Welte + * - added DocBook-style comments for public API * */ #include @@ -29,8 +32,7 @@ #include #include #include -/* For ERR_PTR(). Yeah, I know... --RR */ -#include +#include /* This rwlock protects the main hash table, protocol/helper/expected registrations, conntrack timers*/ @@ -63,6 +65,7 @@ static atomic_t ip_conntrack_count = ATOMIC_INIT(0); struct list_head *ip_conntrack_hash; static kmem_cache_t *ip_conntrack_cachep; +struct ip_conntrack ip_conntrack_untracked; extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; @@ -85,6 +88,10 @@ return p; } +/** + * ip_ct_find_proto - Find layer 4 protocol helper for given protocol number + * @protocol: protocol number + */ struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol) { struct ip_conntrack_protocol *p; @@ -150,6 +157,8 @@ inverse->dst.ip = orig->src.ip; inverse->dst.protonum = orig->dst.protonum; + inverse->src.u.all = inverse->dst.u.all = 0; + return protocol->invert_tuple(inverse, orig); } @@ -342,7 +351,7 @@ atomic_dec(&ip_conntrack_count); } -static void death_by_timeout(unsigned long ul_conntrack) +void ip_ct_death_by_timeout(unsigned long ul_conntrack) { struct ip_conntrack *ct = (void *)ul_conntrack; @@ -377,7 +386,14 @@ return h; } -/* Find a connection corresponding to a tuple. */ +/** + * ip_conntrack_find_get - find conntrack according to tuple + * @tuple: conntrack tuple for which we search conntrack + * @ignored_conntrack: ignore this conntrack during search + * + * This function increments the reference count of the found + * conntrack (if any). + */ struct ip_conntrack_tuple_hash * ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple, const struct ip_conntrack *ignored_conntrack) @@ -405,7 +421,14 @@ return ct; } -/* Return conntrack and conntrack_info given skb->nfct->master */ +/** + * ip_conntrack_get - Return conntrack and conntrack_info for given skb + * @skb: skb for which we want to find conntrack and conntrack_info + * @ctinfo: pointer to ctinfo, used as return value + * + * This function resolves the respective conntrack and conntrack_info + * structures for the connection this packet (skb) is part of. + */ struct ip_conntrack * ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo) { @@ -475,8 +498,14 @@ return NF_DROP; } -/* Returns true if a connection correspondings to the tuple (required - for NAT). */ +/** + * ip_conntrack_tuple_taken - Find out if tuple is already in use + * @tuple: tuple to be used for this test + * @ignored_conntrack: conntrack which is excluded from result + * + * This function is called by the NAT code in order to find out if + * a particular tuple is already in use by some connection. + */ int ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, const struct ip_conntrack *ignored_conntrack) @@ -590,7 +619,7 @@ return dropped; if (del_timer(&h->ctrack->timeout)) { - death_by_timeout((unsigned long)h->ctrack); + ip_ct_death_by_timeout((unsigned long)h->ctrack); dropped = 1; } ip_conntrack_put(h->ctrack); @@ -602,7 +631,13 @@ { return ip_ct_tuple_mask_cmp(rtuple, &i->tuple, &i->mask); } - +/** + * ip_ct_find_helper - Find application helper according to tuple + * @tuple: tuple for which helper needs to be found + * + * This function is used to determine if any registered conntrack helper + * is to be used for the given tuple. + */ struct ip_conntrack_helper *ip_ct_find_helper(const struct ip_conntrack_tuple *tuple) { return LIST_FIND(&helpers, helper_cmp, @@ -676,7 +711,7 @@ /* Don't set timer yet: wait for confirmation */ init_timer(&conntrack->timeout); conntrack->timeout.data = (unsigned long)conntrack; - conntrack->timeout.function = death_by_timeout; + conntrack->timeout.function = ip_ct_death_by_timeout; INIT_LIST_HEAD(&conntrack->sibling_list); @@ -713,6 +748,9 @@ __set_bit(IPS_EXPECTED_BIT, &conntrack->status); conntrack->master = expected; expected->sibling = conntrack; +#if CONFIG_IP_NF_CONNTRACK_MARK + conntrack->mark = expected->expectant->mark; +#endif LIST_DELETE(&ip_conntrack_expect_list, expected); expected->expectant->expecting--; nf_conntrack_get(&master_ct(conntrack)->infos[0]); @@ -790,6 +828,15 @@ int set_reply; int ret; + /* Never happen */ + if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) { + if (net_ratelimit()) { + printk(KERN_ERR "ip_conntrack_in: Frag of proto %u (hook=%u)\n", + (*pskb)->nh.iph->protocol, hooknum); + } + return NF_DROP; + } + /* FIXME: Do this right please. --RR */ (*pskb)->nfcache |= NFC_UNKNOWN; @@ -808,18 +855,10 @@ } #endif - /* Previously seen (loopback)? Ignore. Do this before - fragment check. */ + /* Previously seen (loopback or untracked)? Ignore. */ if ((*pskb)->nfct) return NF_ACCEPT; - /* Gather fragments. */ - if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { - *pskb = ip_ct_gather_frags(*pskb); - if (!*pskb) - return NF_STOLEN; - } - proto = ip_ct_find_proto((*pskb)->nh.iph->protocol); /* It may be an icmp error... */ @@ -896,6 +935,14 @@ return ip_ct_tuple_mask_cmp(&i->tuple, tuple, &intersect_mask); } +/** + * ip_conntrack_unexpect_related - Unexpect a related connection + * @expect: expecattin to be removed + * + * This function removes an existing expectation, that has not yet been + * confirmed (i.e. expectation was issued, but expected connection didn't + * arrive yet) + */ inline void ip_conntrack_unexpect_related(struct ip_conntrack_expect *expect) { WRITE_LOCK(&ip_conntrack_lock); @@ -913,7 +960,20 @@ WRITE_UNLOCK(&ip_conntrack_lock); } -/* Add a related connection. */ +/** + * ip_conntrack_expect_related - Expect a related connection + * @related_to: master conntrack + * @expect: expectation with all values filled in + * + * This function is called by conntrack application helpers who + * have detected that the control (master) connection is just about + * to negotiate a related slave connection. + * + * Note: This function allocates it's own struct ip_conntrack_expect, + * copying the values from the 'expect' parameter. Thus, 'expect' can + * be allocated on the stack and does not need to be valid after this + * function returns. + */ int ip_conntrack_expect_related(struct ip_conntrack *related_to, struct ip_conntrack_expect *expect) { @@ -925,8 +985,8 @@ * so there is no need to use the tuple lock too */ DEBUGP("ip_conntrack_expect_related %p\n", related_to); - DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); - DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); + DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple); + DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask); old = LIST_FIND(&ip_conntrack_expect_list, resent_expect, struct ip_conntrack_expect *, &expect->tuple, @@ -953,7 +1013,6 @@ } } else if (related_to->helper->max_expected && related_to->expecting >= related_to->helper->max_expected) { - struct list_head *cur_item; /* old == NULL */ if (!(related_to->helper->flags & IP_CT_HELPER_F_REUSE_EXPECT)) { @@ -978,21 +1037,14 @@ NIPQUAD(related_to->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip)); /* choose the the oldest expectation to evict */ - list_for_each(cur_item, &related_to->sibling_list) { - struct ip_conntrack_expect *cur; - - cur = list_entry(cur_item, - struct ip_conntrack_expect, - expected_list); - if (cur->sibling == NULL) { - old = cur; + list_for_each_entry(old, &related_to->sibling_list, + expected_list) + if (old->sibling == NULL) break; - } - } - /* (!old) cannot happen, since related_to->expecting is the - * number of unconfirmed expects */ - IP_NF_ASSERT(old); + /* We cannot fail since related_to->expecting is the number + * of unconfirmed expectations */ + IP_NF_ASSERT(old && old->sibling == NULL); /* newnat14 does not reuse the real allocated memory * structures but rather unexpects the old and @@ -1024,7 +1076,7 @@ atomic_set(&new->use, 1); /* add to expected list for this connection */ - list_add(&new->expected_list, &related_to->sibling_list); + list_add_tail(&new->expected_list, &related_to->sibling_list); /* add to global list of expectations */ list_prepend(&ip_conntrack_expect_list, &new->list); /* add and start timer if required */ @@ -1043,7 +1095,15 @@ return ret; } -/* Change tuple in an existing expectation */ +/** + * ip_conntrack_change_expect - Change tuple in existing expectation + * @expect: expectation which is to be changed + * @newtuple: new tuple for expect + * + * This function is mostly called by NAT application helpers, who want to + * change an expectation issued by their respective conntrack application + * helper counterpart. + */ int ip_conntrack_change_expect(struct ip_conntrack_expect *expect, struct ip_conntrack_tuple *newtuple) { @@ -1051,15 +1111,14 @@ MUST_BE_READ_LOCKED(&ip_conntrack_lock); WRITE_LOCK(&ip_conntrack_expect_tuple_lock); - DEBUGP("change_expect:\n"); - DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple); - DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask); - DEBUGP("newtuple: "); DUMP_TUPLE(newtuple); + DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple); + DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask); + DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple); if (expect->ct_tuple.dst.protonum == 0) { /* Never seen before */ DEBUGP("change expect: never seen before\n"); - if (!ip_ct_tuple_equal(&expect->tuple, newtuple) + if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask) && LIST_FIND(&ip_conntrack_expect_list, expect_clash, struct ip_conntrack_expect *, newtuple, &expect->mask)) { /* Force NAT to find an unused tuple */ @@ -1084,8 +1143,15 @@ return ret; } -/* Alter reply tuple (maybe alter helper). If it's already taken, - return 0 and don't do alteration. */ +/** + * ip_conntrack_alter_reply - Alter reply tuple of conntrack + * @conntrack: conntrack whose reply tuple we want to alter + * @newreply: designated reply tuple for this conntrack + * + * This function alters the reply tuple of a conntrack to the given + * newreply tuple. If this newreply tuple is already taken, return 0 + * and don't do alteration + */ int ip_conntrack_alter_reply(struct ip_conntrack *conntrack, const struct ip_conntrack_tuple *newreply) { @@ -1110,6 +1176,13 @@ return 1; } +/** + * ip_conntrack_helper_register - Register a conntrack application helper + * @me: structure describing the helper + * + * This function is called by conntrack application helpers to register + * themselves with the conntrack core. + */ int ip_conntrack_helper_register(struct ip_conntrack_helper *me) { WRITE_LOCK(&ip_conntrack_lock); @@ -1131,6 +1204,13 @@ return 0; } +/** + * ip_conntrack_helper_unregister - Unregister a conntrack application helper + * @me: structure describing the helper + * + * This function is called by conntrack application helpers to unregister + * themselvers from the conntrack core. + */ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) { unsigned int i; @@ -1149,7 +1229,14 @@ synchronize_net(); } -/* Refresh conntrack for this many jiffies. */ +/** + * ip_ct_refresh - Refresh conntrack timer for given conntrack + * @ct: conntrack which we want to refresh + * @extra_jiffies: number of jiffies to add + * + * This function is called by protocol helpers and application helpers in + * order to change the expiration timer of a conntrack entry. + */ void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies) { IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); @@ -1159,8 +1246,10 @@ if (!is_confirmed(ct)) ct->timeout.expires = extra_jiffies; else { - /* Need del_timer for race avoidance (may already be dying). */ - if (del_timer(&ct->timeout)) { + /* Don't update timer for each packet, only if it's been >HZ + * ticks since last update. + * Need del_timer for race avoidance (may already be dying). */ + if (abs(jiffies + extra_jiffies - ct->timeout.expires) >= HZ && del_timer(&ct->timeout)) { ct->timeout.expires = jiffies + extra_jiffies; add_timer(&ct->timeout); } @@ -1168,7 +1257,16 @@ WRITE_UNLOCK(&ip_conntrack_lock); } -/* Returns new sk_buff, or NULL */ + +/** + * ip_ct_gather_frags - Gather fragments of a particular skb + * @skb: pointer to sk_buff of fragmented IP packet + * + * This code is just a wrapper around the defragmentation code in the core IPv4 + * stack. It also takes care of nonlinear skb's. + * + * Returns new sk_buff, or NULL + */ struct sk_buff * ip_ct_gather_frags(struct sk_buff *skb) { @@ -1253,6 +1351,16 @@ return h; } +/** + * ip_ct_selective_cleanup - Selectively delete a set of conntrack entries + * @kill: callback function selecting which entries to delete + * @data: opaque data pointer, becomes 2nd argument for kill function + * + * This function can be used to selectively delete elements of the conntrack + * hashtable. The function iterates over the list of conntrack entries and + * calls the 'kill' function for every entry. If the return value is true, + * the connection is deleted (death_by_timeout). + */ void ip_ct_selective_cleanup(int (*kill)(const struct ip_conntrack *i, void *data), void *data) @@ -1263,7 +1371,7 @@ while ((h = get_next_corpse(kill, data)) != NULL) { /* Time to push up daises... */ if (del_timer(&h->ctrack->timeout)) - death_by_timeout((unsigned long)h->ctrack); + ip_ct_death_by_timeout((unsigned long)h->ctrack); /* ... else the timer will get him soon. */ ip_conntrack_put(h->ctrack); @@ -1419,6 +1527,15 @@ /* For use by ipt_REJECT */ ip_ct_attach = ip_conntrack_attach; + + /* Set up fake conntrack: + - to never be deleted, not in any hashes */ + atomic_set(&ip_conntrack_untracked.ct_general.use, 1); + /* - and look it like as a confirmed connection */ + set_bit(IPS_CONFIRMED_BIT, &ip_conntrack_untracked.status); + /* - and prepare the ctinfo field for NAT. */ + ip_conntrack_untracked.infos[IP_CT_NEW].master = &ip_conntrack_untracked.ct_general; + return ret; err_free_hash: diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_egg.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_egg.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_egg.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_egg.c 2003-12-10 23:13:56.912424080 +0100 @@ -0,0 +1,237 @@ +/* Eggdrop extension for IP connection tracking, Version 0.0.5 + * based on ip_conntrack_irc.c + * + * This module only supports the share userfile-send command, + * used by eggdrops to share it's userfile. + * + * There are no support for NAT at the moment. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * + * please give the ports of all Eggdrops You have running + * on your system, the default port is 3333. + * + * 2001-04-19: Security update. IP addresses are now compared + * to prevent unauthorized "related" access. + * + * 2002-03-25: Harald Welte : + * Port to netfilter 'newnat' API. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_c = 0; +static unsigned int egg_timeout = 300; + +MODULE_AUTHOR("Magnus Sandin "); +MODULE_DESCRIPTION("Eggdrop (userfile-sharing) connection tracking module"); +MODULE_LICENSE("GPL"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of eggdrop servers"); +#endif + +DECLARE_LOCK(ip_egg_lock); +struct module *ip_conntrack_egg = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +int parse_command(char *data, char *data_end, u_int32_t * ip, u_int16_t * port) +/* tries to get the ip_addr and port out of a eggdrop command + return value: -1 on failure, 0 on success + data pointer to first byte of DCC command data + data_end pointer to last byte of dcc command data + ip returns parsed ip of dcc command + port returns parsed port of dcc command */ +{ + if (data > data_end) + return -1; + + *ip = simple_strtoul(data, &data, 10); + + /* skip blanks between ip and port */ + while (*data == ' ' && data < data_end) + data++; + + *port = simple_strtoul(data, &data, 10); + return 0; +} + + +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + char *data = (char *) tcph + tcph->doff * 4; + char *data_limit; + u_int32_t tcplen = len - iph->ihl * 4; + u_int32_t datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + int bytes_scanned = 0; + struct ip_conntrack_expect exp; + + u_int32_t egg_ip; + u_int16_t egg_port; + + DEBUGP("entered\n"); + + /* If packet is coming from IRC server */ + if (dir != IP_CT_DIR_REPLY) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("tcplen = %u\n", (unsigned) tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP("bad csum: %p %u %u.%u.%u.%u -> %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + data_limit = (char *) data + datalen; + while (datalen > 5 && bytes_scanned < 128) { + if (memcmp(data, "s us ", 5)) { + data++; + datalen--; + bytes_scanned++; + continue; + } + + data += 5; + + DEBUGP("Userfile-share found in connection " + "%u.%u.%u.%u -> %u.%u.%u.%u\n", + NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + + if (parse_command((char *) data, data_limit, &egg_ip, + &egg_port)) { + DEBUGP("no data in userfile-share pkt\n"); + return NF_ACCEPT; + } + + memset(&exp, 0, sizeof(exp)); + + if (ct->tuplehash[dir].tuple.src.ip != htonl(egg_ip)) { + if (net_ratelimit()) + printk("Forged Eggdrop command from " + "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + HIPQUAD(egg_ip), egg_port); + return NF_ACCEPT; + } + + exp.tuple.src.ip = iph->daddr; + exp.tuple.src.u.tcp.port = 0; + exp.tuple.dst.ip = htonl(egg_ip); + exp.tuple.dst.u.tcp.port = htons(egg_port); + exp.tuple.dst.protonum = IPPROTO_TCP; + + exp.mask.dst.u.tcp.port = 0xffff; + exp.mask.dst.protonum = 0xffff; + + DEBUGP("expect_related %u.%u.%u.%u:%u - %u.%u.%u.%u:%u\n", + NIPQUAD(t.src.ip), ntohs(t.src.u.tcp.port), + NIPQUAD(t.dst.ip), ntohs(t.dst.u.tcp.port)); + + ip_conntrack_expect_related(ct, &exp); + break; + } + return NF_ACCEPT; +} + +static struct ip_conntrack_helper egg_helpers[MAX_PORTS]; +static char egg_names[MAX_PORTS][14]; /* eggdrop-65535 */ + +static void deregister_helpers(void) { + int i; + + for (i = 0; i < ports_c; i++) { + DEBUGP("unregistering helper for port %d\n", ports[i]); + ip_conntrack_helper_unregister(&egg_helpers[i]); + } +} + +static int __init init(void) +{ + int i, ret; + char *tmpname; + + /* If no port given, default to standard eggdrop port */ + if (ports[0] == 0) + ports[0] = 3333; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + memset(&egg_helpers[i], 0, + sizeof(struct ip_conntrack_helper)); + egg_helpers[i].tuple.src.u.tcp.port = htons(ports[i]); + egg_helpers[i].tuple.dst.protonum = IPPROTO_TCP; + egg_helpers[i].mask.src.u.tcp.port = 0xFFFF; + egg_helpers[i].mask.dst.protonum = 0xFFFF; + egg_helpers[i].max_expected = 1; + egg_helpers[i].timeout = egg_timeout; + egg_helpers[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; + egg_helpers[i].me = THIS_MODULE; + egg_helpers[i].help = help; + + tmpname = &egg_names[i][0]; + if (ports[i] == 3333) + sprintf(tmpname, "eggdrop"); + else + sprintf(tmpname, "eggdrop-%d", ports[i]); + egg_helpers[i].name = tmpname; + + DEBUGP("port #%d: %d\n", i, ports[i]); + + ret = ip_conntrack_helper_register(&egg_helpers[i]); + + if (ret) { + printk("ip_conntrack_egg: ERROR registering helper " + "for port %d\n", ports[i]); + deregister_helpers(); + return 1; + } + ports_c++; + } + return 0; +} + +static void __exit fini(void) +{ + deregister_helpers(); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_h323.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_h323.c 2003-12-10 23:13:58.177231800 +0100 @@ -0,0 +1,308 @@ +/* + * H.323 'brute force' extension for H.323 connection tracking. + * Jozsef Kadlecsik + * + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. + * (http://www.coritel.it/projects/sofia/nat/) + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' + * the unregistered helpers to the conntrack entries. + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); +MODULE_LICENSE("GPL"); + +DECLARE_LOCK(ip_h323_lock); +struct module *ip_conntrack_h323 = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: This should be in userspace. Later. */ +static int h245_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct tcphdr *tcph = (void *)iph + iph->ihl * 4; + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; + unsigned char *data_limit; + u_int32_t tcplen = len - iph->ihl * 4; + u_int32_t datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_ct_h225_master *info = &ct->help.ct_h225_info; + struct ip_conntrack_expect expect, *exp = &expect; + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; + u_int16_t data_port; + u_int32_t data_ip; + unsigned int i; + + DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), + NIPQUAD(iph->daddr), ntohs(tcph->dest)); + + /* Can't track connections formed before we registered */ + if (!info) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header or too short packet? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { + DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcplen, 0))) { + DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + data_limit = (unsigned char *) data + datalen; + /* bytes: 0123 45 + ipadrr port */ + for (i = 0; data < (data_limit - 5); data++, i++) { + data_ip = *((u_int32_t *)data); + if (data_ip == iph->saddr) { + data_port = *((u_int16_t *)(data + 4)); + memset(&expect, 0, sizeof(expect)); + /* update the H.225 info */ + DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), + NIPQUAD(iph->saddr), ntohs(data_port)); + LOCK_BH(&ip_h323_lock); + info->is_h225 = H225_PORT + 1; + exp_info->port = data_port; + exp_info->dir = dir; + exp_info->offset = i; + + exp->seq = ntohl(tcph->seq) + i; + + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, + { 0 } }, + { data_ip, + { .tcp = { data_port } }, + IPPROTO_UDP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); + + exp->expectfn = NULL; + + /* Ignore failure; should only happen with NAT */ + ip_conntrack_expect_related(ct, exp); + + UNLOCK_BH(&ip_h323_lock); + } + } + + return NF_ACCEPT; + +} + +/* H.245 helper is not registered! */ +static struct ip_conntrack_helper h245 = + { { NULL, NULL }, + "H.245", /* name */ + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ + NULL, /* module */ + 8, /* max_ expected */ + 240, /* timeout */ + { { 0, { 0 } }, /* tuple */ + { 0, { 0 }, IPPROTO_TCP } }, + { { 0, { 0xFFFF } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + h245_help /* helper */ + }; + +static int h225_expect(struct ip_conntrack *ct) +{ + WRITE_LOCK(&ip_conntrack_lock); + ct->helper = &h245; + DEBUGP("h225_expect: helper for %p added\n", ct); + WRITE_UNLOCK(&ip_conntrack_lock); + + return NF_ACCEPT; /* unused */ +} + +/* FIXME: This should be in userspace. Later. */ +static int h225_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct tcphdr *tcph = (void *)iph + iph->ihl * 4; + unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; + unsigned char *data_limit; + u_int32_t tcplen = len - iph->ihl * 4; + u_int32_t datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_ct_h225_master *info = &ct->help.ct_h225_info; + struct ip_conntrack_expect expect, *exp = &expect; + struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; + u_int16_t data_port; + u_int32_t data_ip; + unsigned int i; + + DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), + NIPQUAD(iph->daddr), ntohs(tcph->dest)); + + /* Can't track connections formed before we registered */ + if (!info) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header or too short packet? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { + DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcplen, 0))) { + DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + data_limit = (unsigned char *) data + datalen; + /* bytes: 0123 45 + ipadrr port */ + for (i = 0; data < (data_limit - 5); data++, i++) { + data_ip = *((u_int32_t *)data); + if (data_ip == iph->saddr) { + data_port = *((u_int16_t *)(data + 4)); + if (data_port == tcph->source) { + /* Signal address */ + DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n", + NIPQUAD(iph->saddr)); + /* Update the H.225 info so that NAT can mangle the address/port + even when we have no expected connection! */ +#ifdef CONFIG_IP_NF_NAT_NEEDED + LOCK_BH(&ip_h323_lock); + info->dir = dir; + info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i; + info->offset[IP_CT_DIR_ORIGINAL] = i; + UNLOCK_BH(&ip_h323_lock); +#endif + } else { + memset(&expect, 0, sizeof(expect)); + + /* update the H.225 info */ + LOCK_BH(&ip_h323_lock); + info->is_h225 = H225_PORT; + exp_info->port = data_port; + exp_info->dir = dir; + exp_info->offset = i; + + exp->seq = ntohl(tcph->seq) + i; + + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, + { 0 } }, + { data_ip, + { .tcp = { data_port } }, + IPPROTO_TCP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); + + exp->expectfn = h225_expect; + + /* Ignore failure */ + ip_conntrack_expect_related(ct, exp); + + DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), + NIPQUAD(iph->saddr), ntohs(data_port)); + + UNLOCK_BH(&ip_h323_lock); + } +#ifdef CONFIG_IP_NF_NAT_NEEDED + } else if (data_ip == iph->daddr) { + data_port = *((u_int16_t *)(data + 4)); + if (data_port == tcph->dest) { + /* Signal address */ + DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n", + NIPQUAD(iph->daddr)); + /* Update the H.225 info so that NAT can mangle the address/port + even when we have no expected connection! */ + LOCK_BH(&ip_h323_lock); + info->dir = dir; + info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i; + info->offset[IP_CT_DIR_REPLY] = i; + UNLOCK_BH(&ip_h323_lock); + } +#endif + } + } + + return NF_ACCEPT; + +} + +static struct ip_conntrack_helper h225 = + { { NULL, NULL }, + "H.225", /* name */ + IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ + THIS_MODULE, /* module */ + 2, /* max_expected */ + 240, /* timeout */ + { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ + { 0, { 0 }, IPPROTO_TCP } }, + { { 0, { 0xFFFF } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + h225_help /* helper */ + }; + +static int __init init(void) +{ + return ip_conntrack_helper_register(&h225); +} + +static void __exit fini(void) +{ + /* Unregister H.225 helper */ + ip_conntrack_helper_unregister(&h225); +} + +EXPORT_SYMBOL(ip_h323_lock); + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_mms.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_mms.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_mms.c 2003-12-10 23:14:02.756535640 +0100 @@ -0,0 +1,308 @@ +/* MMS extension for IP connection tracking + * (C) 2002 by Filip Sneppe + * based on ip_conntrack_ftp.c and ip_conntrack_irc.c + * + * ip_conntrack_mms.c v0.3 2002-09-22 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_conntrack_mms.o ports=port1,port2,...port + * + * Please give the ports of all MMS servers You wish to connect to. + * If you don't specify ports, the default will be TCP port 1755. + * + * More info on MMS protocol, firewalls and NAT: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp + * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp + * + * The SDP project people are reverse-engineering MMS: + * http://get.to/sdp + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +DECLARE_LOCK(ip_mms_lock); +struct module *ip_conntrack_mms = THIS_MODULE; + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_c; +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +#endif + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +EXPORT_SYMBOL(ip_mms_lock); + +MODULE_AUTHOR("Filip Sneppe "); +MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module"); +MODULE_LICENSE("GPL"); + +/* #define isdigit(c) (c >= '0' && c <= '9') */ + +/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */ +static void unicode_to_ascii (char *string, short *unicode, int unicode_size) +{ + int i; + for (i = 0; i < unicode_size; ++i) { + string[i] = (char)(unicode[i]); + } + string[unicode_size] = 0x00; +} + +__inline static int atoi(char *s) +{ + int i=0; + while (isdigit(*s)) { + i = i*10 + *(s++) - '0'; + } + return i; +} + +/* convert ip address string like "192.168.0.10" to unsigned int */ +__inline static u_int32_t asciiiptoi(char *s) +{ + unsigned int i, j, k; + + for(i=k=0; k<3; ++k, ++s, i<<=8) { + i+=atoi(s); + for(j=0; (*(++s) != '.') && (j<3); ++j) + ; + } + i+=atoi(s); + return ntohl(i); +} + +int parse_mms(const char *data, + const unsigned int datalen, + u_int32_t *mms_ip, + u_int16_t *mms_proto, + u_int16_t *mms_port, + char **mms_string_b, + char **mms_string_e, + char **mms_padding_e) +{ + int unicode_size, i; + char tempstring[28]; /* "\\255.255.255.255\UDP\65535" */ + char getlengthstring[28]; + + for(unicode_size=0; + (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0; + unicode_size++) + if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen)) + return -1; /* out of bounds - incomplete packet */ + + unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size); + DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring)); + + /* IP address ? */ + *mms_ip = asciiiptoi(tempstring+2); + + i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip)); + + /* protocol ? */ + if(strncmp(tempstring+3+i, "TCP", 3)==0) + *mms_proto = IPPROTO_TCP; + else if(strncmp(tempstring+3+i, "UDP", 3)==0) + *mms_proto = IPPROTO_UDP; + + /* port ? */ + *mms_port = atoi(tempstring+7+i); + + /* we store a pointer to the beginning of the "\\a.b.c.d\proto\port" + unicode string, one to the end of the string, and one to the end + of the packet, since we must keep track of the number of bytes + between end of the unicode string and the end of packet (padding) */ + *mms_string_b = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET); + *mms_string_e = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2); + *mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */ + return 0; +} + + +/* FIXME: This should be in userspace. Later. */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guaranteed by ip_conntrack_tcp.c */ + struct tcphdr *tcph = (void *)iph + iph->ihl * 4; + const char *data = (const char *)tcph + tcph->doff * 4; + unsigned int tcplen = len - iph->ihl * 4; + unsigned int datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_expect expect, *exp = &expect; + struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info; + + u_int32_t mms_ip; + u_int16_t mms_proto; + char mms_proto_string[8]; + u_int16_t mms_port; + char *mms_string_b, *mms_string_e, *mms_padding_e; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { + DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) { + DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcplen, 0))) { + DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */ + /* FIXME: There is an issue with only looking at this packet: before this packet, + the client has already sent a packet to the server with the server's hostname + according to the client (think of it as the "Host: " header in HTTP/1.1). The + server will break the connection if this doesn't correspond to its own host + header. The client can also connect to an IP address; if it's the server's IP + address, it will not break the connection. When doing DNAT on a connection + where the client uses a server's IP address, the nat module should detect + this and change this string accordingly to the DNATed address. This should + probably be done by checking for an IP address, then storing it as a member + of struct ip_ct_mms_expect and checking for it in ip_nat_mms... + */ + if( (MMS_SRV_MSG_OFFSET < datalen) && + ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) { + DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", + (u8)*(data+36), (u8)*(data+37), + (u8)*(data+38), (u8)*(data+39), + datalen); + if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port, + &mms_string_b, &mms_string_e, &mms_padding_e)) + if(net_ratelimit()) + /* FIXME: more verbose debugging ? */ + printk(KERN_WARNING + "ip_conntrack_mms: Unable to parse data payload\n"); + + memset(&expect, 0, sizeof(expect)); + + sprintf(mms_proto_string, "(%u)", mms_proto); + DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n", + mms_proto == IPPROTO_TCP ? "TCP" + : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string, + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), + NIPQUAD(mms_ip), + mms_port); + + /* it's possible that the client will just ask the server to tunnel + the stream over the same TCP session (from port 1755): there's + shouldn't be a need to add an expectation in that case, but it + makes NAT packet mangling so much easier */ + LOCK_BH(&ip_mms_lock); + + DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq); + + exp->seq = ntohl(tcph->seq) + (mms_string_b - data); + exp_mms_info->len = (mms_string_e - mms_string_b); + exp_mms_info->padding = (mms_padding_e - mms_string_e); + exp_mms_info->port = mms_port; + + DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n", + exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding); + + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, + { mms_ip, + { .tcp = { (__u16) ntohs(mms_port) } }, + mms_proto } } + ); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); + exp->expectfn = NULL; + ip_conntrack_expect_related(ct, &expect); + UNLOCK_BH(&ip_mms_lock); + } + + return NF_ACCEPT; +} + +static struct ip_conntrack_helper mms[MAX_PORTS]; +static char mms_names[MAX_PORTS][10]; + +/* Not __exit: called from init() */ +static void fini(void) +{ + int i; + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n", + ports[i]); + ip_conntrack_helper_unregister(&mms[i]); + } +} + +static int __init init(void) +{ + int i, ret; + char *tmpname; + + if (ports[0] == 0) + ports[0] = MMS_PORT; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + memset(&mms[i], 0, sizeof(struct ip_conntrack_helper)); + mms[i].tuple.src.u.tcp.port = htons(ports[i]); + mms[i].tuple.dst.protonum = IPPROTO_TCP; + mms[i].mask.src.u.tcp.port = 0xFFFF; + mms[i].mask.dst.protonum = 0xFFFF; + mms[i].max_expected = 1; + mms[i].timeout = 0; + mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; + mms[i].me = THIS_MODULE; + mms[i].help = help; + + tmpname = &mms_names[i][0]; + if (ports[i] == MMS_PORT) + sprintf(tmpname, "mms"); + else + sprintf(tmpname, "mms-%d", ports[i]); + mms[i].name = tmpname; + + DEBUGP("ip_conntrack_mms: registering helper for port %d\n", + ports[i]); + ret = ip_conntrack_helper_register(&mms[i]); + + if (ret) { + fini(); + return ret; + } + ports_c++; + } + return 0; +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_pptp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_pptp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_pptp.c 2003-12-10 23:14:24.102290592 +0100 @@ -0,0 +1,639 @@ +/* + * ip_conntrack_pptp.c - Version 1.9 + * + * Connection tracking support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2003 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * Limitations: + * - We blindly assume that control connections are always + * established in PNS->PAC direction. This is a violation + * of RFFC2673 + * + * TODO: - finish support for multiple calls within one session + * (needs expect reservations in newnat) + * - testing of incoming PPTP calls + * + * Changes: + * 2002-02-05 - Version 1.3 + * - Call ip_conntrack_unexpect_related() from + * pptp_timeout_related() to destroy expectations in case + * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen + * (Philip Craig ) + * - Add Version information at module loadtime + * 2002-02-10 - Version 1.6 + * - move to C99 style initializers + * - remove second expectation if first arrives + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define IP_CT_PPTP_VERSION "1.9" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); + +DECLARE_LOCK(ip_pptp_lock); + +#if 0 +#include "ip_conntrack_pptp_priv.h" +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ": " format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +#define SECS *HZ +#define MINS * 60 SECS +#define HOURS * 60 MINS +#define DAYS * 24 HOURS + +#define PPTP_GRE_TIMEOUT (10 MINS) +#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS) + +static int pptp_expectfn(struct ip_conntrack *ct) +{ + struct ip_conntrack *master; + struct ip_conntrack_expect *exp; + + DEBUGP("increasing timeouts\n"); + /* increase timeout of GRE data channel conntrack entry */ + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; + + master = master_ct(ct); + if (!master) { + DEBUGP(" no master!!!\n"); + return 0; + } + + exp = ct->master; + if (!exp) { + DEBUGP("no expectation!!\n"); + return 0; + } + + DEBUGP("completing tuples with ct info\n"); + /* we can do this, since we're unconfirmed */ + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == + htonl(master->help.ct_pptp_info.pac_call_id)) { + /* assume PNS->PAC */ + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = + htonl(master->help.ct_pptp_info.pns_call_id); + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = + htonl(master->help.ct_pptp_info.pns_call_id); + } else { + /* assume PAC->PNS */ + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = + htonl(master->help.ct_pptp_info.pac_call_id); + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = + htonl(master->help.ct_pptp_info.pac_call_id); + } + + /* delete other expectation */ + if (exp->expected_list.next != &exp->expected_list) { + struct ip_conntrack_expect *other_exp; + struct list_head *cur_item, *next; + + for (cur_item = master->sibling_list.next; + cur_item != &master->sibling_list; cur_item = next) { + next = cur_item->next; + other_exp = list_entry(cur_item, + struct ip_conntrack_expect, + expected_list); + /* remove only if occurred at same sequence number */ + if (other_exp != exp && other_exp->seq == exp->seq) { + DEBUGP("unexpecting other direction\n"); + ip_ct_gre_keymap_destroy(other_exp); + ip_conntrack_unexpect_related(other_exp); + } + } + } + + return 0; +} + +/* timeout GRE data connections */ +static int pptp_timeout_related(struct ip_conntrack *ct) +{ + struct list_head *cur_item, *next; + struct ip_conntrack_expect *exp; + + /* FIXME: do we have to lock something ? */ + for (cur_item = ct->sibling_list.next; + cur_item != &ct->sibling_list; cur_item = next) { + next = cur_item->next; + exp = list_entry(cur_item, struct ip_conntrack_expect, + expected_list); + + ip_ct_gre_keymap_destroy(exp); + if (!exp->sibling) { + ip_conntrack_unexpect_related(exp); + continue; + } + + DEBUGP("killing conntrack %p\n", + exp->sibling); + exp->sibling->proto.gre.timeout = 0; + exp->sibling->proto.gre.stream_timeout = 0; + + if (del_timer(&exp->sibling->timeout)) + ip_ct_death_by_timeout((unsigned long)exp->sibling); + } + + return 0; +} + +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ +static inline int +exp_gre(struct ip_conntrack *master, + u_int32_t seq, + u_int16_t callid, + u_int16_t peer_callid) +{ + struct ip_conntrack_expect exp; + struct ip_conntrack_tuple inv_tuple; + + memset(&exp, 0, sizeof(exp)); + /* tuple in original direction, PNS->PAC */ + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid)); + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + exp.tuple.dst.u.gre.key = htonl(ntohs(callid)); + exp.tuple.dst.u.gre.protocol = __constant_htons(GRE_PROTOCOL_PPTP); + exp.tuple.dst.u.gre.version = GRE_VERSION_PPTP; + exp.tuple.dst.protonum = IPPROTO_GRE; + + exp.mask.src.ip = 0xffffffff; + exp.mask.src.u.all = 0; + exp.mask.dst.u.all = 0; + exp.mask.dst.u.gre.key = 0xffffffff; + exp.mask.dst.u.gre.version = 0xff; + exp.mask.dst.u.gre.protocol = 0xffff; + exp.mask.dst.ip = 0xffffffff; + exp.mask.dst.protonum = 0xffff; + + exp.seq = seq; + exp.expectfn = pptp_expectfn; + + exp.help.exp_pptp_info.pac_call_id = ntohs(callid); + exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid); + + DEBUGP("calling expect_related "); + DUMP_TUPLE_RAW(&exp.tuple); + + /* Add GRE keymap entries */ + if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0) + return 1; + + invert_tuplepr(&inv_tuple, &exp.tuple); + if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) { + ip_ct_gre_keymap_destroy(&exp); + return 1; + } + + if (ip_conntrack_expect_related(master, &exp) != 0) { + ip_ct_gre_keymap_destroy(&exp); + DEBUGP("cannot expect_related()\n"); + return 1; + } + + /* tuple in reply direction, PAC->PNS */ + exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + exp.tuple.src.u.gre.key = htonl(ntohs(callid)); + exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid)); + + DEBUGP("calling expect_related "); + DUMP_TUPLE_RAW(&exp.tuple); + + /* Add GRE keymap entries */ + ip_ct_gre_keymap_add(&exp, &exp.tuple, 0); + invert_tuplepr(&inv_tuple, &exp.tuple); + ip_ct_gre_keymap_add(&exp, &inv_tuple, 1); + /* FIXME: cannot handle error correctly, since we need to free + * the above keymap :( */ + + if (ip_conntrack_expect_related(master, &exp) != 0) { + /* free the second pair of keypmaps */ + ip_ct_gre_keymap_destroy(&exp); + DEBUGP("cannot expect_related():\n"); + return 1; + } + + return 0; +} + +static inline int +pptp_inbound_pkt(struct tcphdr *tcph, + struct pptp_pkt_hdr *pptph, + size_t datalen, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct PptpControlHeader *ctlh; + union pptp_ctrl_union pptpReq; + + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; + u_int16_t msg, *cid, *pcid; + u_int32_t seq; + + ctlh = (struct PptpControlHeader *) + ((char *) pptph + sizeof(struct pptp_pkt_hdr)); + pptpReq.rawreq = (void *) + ((char *) ctlh + sizeof(struct PptpControlHeader)); + + msg = ntohs(ctlh->messageType); + DEBUGP("inbound control message %s\n", strMName[msg]); + + switch (msg) { + case PPTP_START_SESSION_REPLY: + /* server confirms new control session */ + if (info->sstate < PPTP_SESSION_REQUESTED) { + DEBUGP("%s without START_SESS_REQUEST\n", + strMName[msg]); + break; + } + if (pptpReq.srep->resultCode == PPTP_START_OK) + info->sstate = PPTP_SESSION_CONFIRMED; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_STOP_SESSION_REPLY: + /* server confirms end of control session */ + if (info->sstate > PPTP_SESSION_STOPREQ) { + DEBUGP("%s without STOP_SESS_REQUEST\n", + strMName[msg]); + break; + } + if (pptpReq.strep->resultCode == PPTP_STOP_OK) + info->sstate = PPTP_SESSION_NONE; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_OUT_CALL_REPLY: + /* server accepted call, we now expect GRE frames */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", strMName[msg]); + break; + } + if (info->cstate != PPTP_CALL_OUT_REQ && + info->cstate != PPTP_CALL_OUT_CONF) { + DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]); + break; + } + if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) { + info->cstate = PPTP_CALL_NONE; + break; + } + + cid = &pptpReq.ocack->callID; + pcid = &pptpReq.ocack->peersCallID; + + info->pac_call_id = ntohs(*cid); + + if (htons(info->pns_call_id) != *pcid) { + DEBUGP("%s for unknown callid %u\n", + strMName[msg], ntohs(*pcid)); + break; + } + + DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], + ntohs(*cid), ntohs(*pcid)); + + info->cstate = PPTP_CALL_OUT_CONF; + + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); + if (exp_gre(ct, seq, *cid, *pcid) != 0) + printk("ip_conntrack_pptp: error during exp_gre\n"); + break; + + case PPTP_IN_CALL_REQUEST: + /* server tells us about incoming call request */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", strMName[msg]); + break; + } + pcid = &pptpReq.icack->peersCallID; + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); + info->cstate = PPTP_CALL_IN_REQ; + info->pac_call_id= ntohs(*pcid); + break; + + case PPTP_IN_CALL_CONNECT: + /* server tells us about incoming call established */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", strMName[msg]); + break; + } + if (info->sstate != PPTP_CALL_IN_REP + && info->sstate != PPTP_CALL_IN_CONF) { + DEBUGP("%s but never sent IN_CALL_REPLY\n", + strMName[msg]); + break; + } + + pcid = &pptpReq.iccon->peersCallID; + cid = &info->pac_call_id; + + if (info->pns_call_id != ntohs(*pcid)) { + DEBUGP("%s for unknown CallID %u\n", + strMName[msg], ntohs(*cid)); + break; + } + + DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); + info->cstate = PPTP_CALL_IN_CONF; + + /* we expect a GRE connection from PAC to PNS */ + seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); + if (exp_gre(ct, seq, *cid, *pcid) != 0) + printk("ip_conntrack_pptp: error during exp_gre\n"); + + break; + + case PPTP_CALL_DISCONNECT_NOTIFY: + /* server confirms disconnect */ + cid = &pptpReq.disc->callID; + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); + info->cstate = PPTP_CALL_NONE; + + /* untrack this call id, unexpect GRE packets */ + pptp_timeout_related(ct); + break; + + case PPTP_WAN_ERROR_NOTIFY: + break; + + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + default: + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) + ? strMName[msg]:strMName[0], msg); + break; + } + + return NF_ACCEPT; + +} + +static inline int +pptp_outbound_pkt(struct tcphdr *tcph, + struct pptp_pkt_hdr *pptph, + size_t datalen, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct PptpControlHeader *ctlh; + union pptp_ctrl_union pptpReq; + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; + u_int16_t msg, *cid, *pcid; + + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); + + msg = ntohs(ctlh->messageType); + DEBUGP("outbound control message %s\n", strMName[msg]); + + switch (msg) { + case PPTP_START_SESSION_REQUEST: + /* client requests for new control session */ + if (info->sstate != PPTP_SESSION_NONE) { + DEBUGP("%s but we already have one", + strMName[msg]); + } + info->sstate = PPTP_SESSION_REQUESTED; + break; + case PPTP_STOP_SESSION_REQUEST: + /* client requests end of control session */ + info->sstate = PPTP_SESSION_STOPREQ; + break; + + case PPTP_OUT_CALL_REQUEST: + /* client initiating connection to server */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", + strMName[msg]); + break; + } + info->cstate = PPTP_CALL_OUT_REQ; + /* track PNS call id */ + cid = &pptpReq.ocreq->callID; + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); + info->pns_call_id = ntohs(*cid); + break; + case PPTP_IN_CALL_REPLY: + /* client answers incoming call */ + if (info->cstate != PPTP_CALL_IN_REQ + && info->cstate != PPTP_CALL_IN_REP) { + DEBUGP("%s without incall_req\n", + strMName[msg]); + break; + } + if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) { + info->cstate = PPTP_CALL_NONE; + break; + } + pcid = &pptpReq.icack->peersCallID; + if (info->pac_call_id != ntohs(*pcid)) { + DEBUGP("%s for unknown call %u\n", + strMName[msg], ntohs(*pcid)); + break; + } + DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid)); + /* part two of the three-way handshake */ + info->cstate = PPTP_CALL_IN_REP; + info->pns_call_id = ntohs(pptpReq.icack->callID); + break; + + case PPTP_CALL_CLEAR_REQUEST: + /* client requests hangup of call */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("CLEAR_CALL but no session\n"); + break; + } + /* FUTURE: iterate over all calls and check if + * call ID is valid. We don't do this without newnat, + * because we only know about last call */ + info->cstate = PPTP_CALL_CLEAR_REQ; + break; + case PPTP_SET_LINK_INFO: + break; + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + default: + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? + strMName[msg]:strMName[0], msg); + /* unknown: no need to create GRE masq table entry */ + break; + } + + return NF_ACCEPT; +} + + +/* track caller id inside control connection, call expect_related */ +static int +conntrack_pptp_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) + +{ + struct pptp_pkt_hdr *pptph; + + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + u_int32_t tcplen = len - iph->ihl * 4; + u_int32_t datalen = tcplen - tcph->doff * 4; + void *datalimit; + int dir = CTINFO2DIR(ctinfo); + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; + + int oldsstate, oldcstate; + int ret; + + /* don't do any tracking before tcp handshake complete */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { + DEBUGP("ctinfo = %u, skipping\n", ctinfo); + return NF_ACCEPT; + } + + /* not a complete TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("tcplen = %u\n", tcplen); + return NF_ACCEPT; + } + + /* checksum invalid? */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + printk(KERN_NOTICE __FILE__ ": bad csum\n"); + /* W2K PPTP server sends TCP packets with wrong checksum :(( */ + //return NF_ACCEPT; + } + + if (tcph->fin || tcph->rst) { + DEBUGP("RST/FIN received, timeouting GRE\n"); + /* can't do this after real newnat */ + info->cstate = PPTP_CALL_NONE; + + /* untrack this call id, unexpect GRE packets */ + pptp_timeout_related(ct); + } + + + pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4); + datalimit = (void *) pptph + datalen; + + /* not a full pptp packet header? */ + if ((void *) pptph+sizeof(*pptph) >= datalimit) { + DEBUGP("no full PPTP header, can't track\n"); + return NF_ACCEPT; + } + + /* if it's not a control message we can't do anything with it */ + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { + DEBUGP("not a control packet\n"); + return NF_ACCEPT; + } + + oldsstate = info->sstate; + oldcstate = info->cstate; + + LOCK_BH(&ip_pptp_lock); + + /* FIXME: We just blindly assume that the control connection is always + * established from PNS->PAC. However, RFC makes no guarantee */ + if (dir == IP_CT_DIR_ORIGINAL) + /* client -> server (PNS -> PAC) */ + ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); + else + /* server -> client (PAC -> PNS) */ + ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo); + DEBUGP("sstate: %d->%d, cstate: %d->%d\n", + oldsstate, info->sstate, oldcstate, info->cstate); + UNLOCK_BH(&ip_pptp_lock); + + return ret; +} + +/* control protocol helper */ +static struct ip_conntrack_helper pptp = { + .list = { NULL, NULL }, + .name = "pptp", + .flags = IP_CT_HELPER_F_REUSE_EXPECT, + .me = THIS_MODULE, + .max_expected = 2, + .timeout = 0, + .tuple = { .src = { .ip = 0, + .u = { .tcp = { .port = + __constant_htons(PPTP_CONTROL_PORT) } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = IPPROTO_TCP + } + }, + .mask = { .src = { .ip = 0, + .u = { .tcp = { .port = 0xffff } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = 0xffff + } + }, + .help = conntrack_pptp_help +}; + +/* ip_conntrack_pptp initialization */ +static int __init init(void) +{ + int retcode; + + DEBUGP(__FILE__ ": registering helper\n"); + if ((retcode = ip_conntrack_helper_register(&pptp))) { + printk(KERN_ERR "Unable to register conntrack application " + "helper for pptp: %d\n", retcode); + return -EIO; + } + + printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); + return 0; +} + +static void __exit fini(void) +{ + ip_conntrack_helper_unregister(&pptp); + printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); +} + +module_init(init); +module_exit(fini); + +EXPORT_SYMBOL(ip_pptp_lock); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_pptp_priv.h --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2003-11-17 09:09:34.000000000 +0100 @@ -0,0 +1,24 @@ +#ifndef _IP_CT_PPTP_PRIV_H +#define _IP_CT_PPTP_PRIV_H + +/* PptpControlMessageType names */ +static const char *strMName[] = { + "UNKNOWN_MESSAGE", + "START_SESSION_REQUEST", + "START_SESSION_REPLY", + "STOP_SESSION_REQUEST", + "STOP_SESSION_REPLY", + "ECHO_REQUEST", + "ECHO_REPLY", + "OUT_CALL_REQUEST", + "OUT_CALL_REPLY", + "IN_CALL_REQUEST", + "IN_CALL_REPLY", + "IN_CALL_CONNECT", + "CALL_CLEAR_REQUEST", + "CALL_DISCONNECT_NOTIFY", + "WAN_ERROR_NOTIFY", + "SET_LINK_INFO" +}; + +#endif diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_proto_gre.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2003-11-17 09:09:34.000000000 +0100 @@ -0,0 +1,343 @@ +/* + * ip_conntrack_proto_gre.c - Version 1.2 + * + * Connection tracking protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2003 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DECLARE_RWLOCK(ip_ct_gre_lock); +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock) +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock) + +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); + +/* shamelessly stolen from ip_conntrack_proto_udp.c */ +#define GRE_TIMEOUT (30*HZ) +#define GRE_STREAM_TIMEOUT (180*HZ) + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ": " format, ## args) +#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \ + NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \ + NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key), \ + (x)->dst.u.gre.version, \ + ntohs((x)->dst.u.gre.protocol)) +#else +#define DEBUGP(x, args...) +#define DUMP_TUPLE_GRE(x) +#endif + +/* GRE KEYMAP HANDLING FUNCTIONS */ +static LIST_HEAD(gre_keymap_list); + +static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, + const struct ip_conntrack_tuple *t) +{ + return ((km->tuple.src.ip == t->src.ip) && + (km->tuple.dst.ip == t->dst.ip) && + (km->tuple.dst.protonum == t->dst.protonum) && + (km->tuple.dst.u.all == t->dst.u.all)); +} + +/* look up the source key for a given tuple */ +static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) +{ + struct ip_ct_gre_keymap *km; + u_int32_t key; + + READ_LOCK(&ip_ct_gre_lock); + km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, + struct ip_ct_gre_keymap *, t); + if (!km) { + READ_UNLOCK(&ip_ct_gre_lock); + return 0; + } + + key = km->tuple.src.u.gre.key; + READ_UNLOCK(&ip_ct_gre_lock); + + return key; +} + +/* add a single keymap entry, associate with specified expect */ +int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, + struct ip_conntrack_tuple *t, int reply) +{ + struct ip_ct_gre_keymap *km; + + km = kmalloc(sizeof(*km), GFP_ATOMIC); + if (!km) + return -1; + + /* initializing list head should be sufficient */ + memset(km, 0, sizeof(*km)); + + memcpy(&km->tuple, t, sizeof(*t)); + + if (!reply) + exp->proto.gre.keymap_orig = km; + else + exp->proto.gre.keymap_reply = km; + + DEBUGP("adding new entry %p: ", km); + DUMP_TUPLE_GRE(&km->tuple); + + WRITE_LOCK(&ip_ct_gre_lock); + list_append(&gre_keymap_list, km); + WRITE_UNLOCK(&ip_ct_gre_lock); + + return 0; +} + +/* change the tuple of a keymap entry (used by nat helper) */ +void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, + struct ip_conntrack_tuple *t) +{ + DEBUGP("changing entry %p to: ", km); + DUMP_TUPLE_GRE(t); + + WRITE_LOCK(&ip_ct_gre_lock); + memcpy(&km->tuple, t, sizeof(km->tuple)); + WRITE_UNLOCK(&ip_ct_gre_lock); +} + +/* destroy the keymap entries associated with specified expect */ +void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp) +{ + DEBUGP("entering for exp %p\n", exp); + WRITE_LOCK(&ip_ct_gre_lock); + if (exp->proto.gre.keymap_orig) { + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig); + list_del(&exp->proto.gre.keymap_orig->list); + kfree(exp->proto.gre.keymap_orig); + exp->proto.gre.keymap_orig = NULL; + } + if (exp->proto.gre.keymap_reply) { + DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply); + list_del(&exp->proto.gre.keymap_reply->list); + kfree(exp->proto.gre.keymap_reply); + exp->proto.gre.keymap_reply = NULL; + } + WRITE_UNLOCK(&ip_ct_gre_lock); +} + + +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ + +/* invert gre part of tuple */ +static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, + const struct ip_conntrack_tuple *orig) +{ + tuple->dst.u.gre.protocol = orig->dst.u.gre.protocol; + tuple->dst.u.gre.version = orig->dst.u.gre.version; + + tuple->dst.u.gre.key = orig->src.u.gre.key; + tuple->src.u.gre.key = orig->dst.u.gre.key; + + return 1; +} + +/* gre hdr info to tuple */ +static int gre_pkt_to_tuple(const void *datah, size_t datalen, + struct ip_conntrack_tuple *tuple) +{ + struct gre_hdr *grehdr = (struct gre_hdr *) datah; + struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah; + u_int32_t srckey; + + /* core guarantees 8 protocol bytes, no need for size check */ + + tuple->dst.u.gre.version = grehdr->version; + tuple->dst.u.gre.protocol = grehdr->protocol; + + switch (grehdr->version) { + case GRE_VERSION_1701: + if (!grehdr->key) { + DEBUGP("Can't track GRE without key\n"); + return 0; + } + tuple->dst.u.gre.key = *(gre_key(grehdr)); + break; + + case GRE_VERSION_PPTP: + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { + DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); + return 0; + } + tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id)); + break; + + default: + printk(KERN_WARNING "unknown GRE version %hu\n", + tuple->dst.u.gre.version); + return 0; + } + + srckey = gre_keymap_lookup(tuple); + +#if 0 + DEBUGP("found src key %x for tuple ", ntohl(srckey)); + DUMP_TUPLE_GRE(tuple); +#endif + tuple->src.u.gre.key = srckey; + + return 1; +} + +/* print gre part of tuple */ +static unsigned int gre_print_tuple(char *buffer, + const struct ip_conntrack_tuple *tuple) +{ + return sprintf(buffer, "version=%d protocol=0x%04x srckey=0x%x dstkey=0x%x ", + tuple->dst.u.gre.version, + ntohs(tuple->dst.u.gre.protocol), + ntohl(tuple->src.u.gre.key), + ntohl(tuple->dst.u.gre.key)); +} + +/* print private data for conntrack */ +static unsigned int gre_print_conntrack(char *buffer, + const struct ip_conntrack *ct) +{ + return sprintf(buffer, "timeout=%u, stream_timeout=%u ", + (ct->proto.gre.timeout / HZ), + (ct->proto.gre.stream_timeout / HZ)); +} + +/* Returns verdict for packet, and may modify conntrack */ +static int gre_packet(struct ip_conntrack *ct, + struct iphdr *iph, size_t len, + enum ip_conntrack_info conntrackinfo) +{ + /* If we've seen traffic both ways, this is a GRE connection. + * Extend timeout. */ + if (ct->status & IPS_SEEN_REPLY) { + ip_ct_refresh(ct, ct->proto.gre.stream_timeout); + /* Also, more likely to be important, and not a probe. */ + set_bit(IPS_ASSURED_BIT, &ct->status); + } else + ip_ct_refresh(ct, ct->proto.gre.timeout); + + return NF_ACCEPT; +} + +/* Called when a new connection for this protocol found. */ +static int gre_new(struct ip_conntrack *ct, + struct iphdr *iph, size_t len) +{ + DEBUGP(": "); + DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + + /* initialize to sane value. Ideally a conntrack helper + * (e.g. in case of pptp) is increasing them */ + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; + ct->proto.gre.timeout = GRE_TIMEOUT; + + return 1; +} + +/* Called when a conntrack entry has already been removed from the hashes + * and is about to be deleted from memory */ +static void gre_destroy(struct ip_conntrack *ct) +{ + struct ip_conntrack_expect *master = ct->master; + + DEBUGP(" entering\n"); + + if (!master) { + DEBUGP("no master exp for ct %p\n", ct); + return; + } + + ip_ct_gre_keymap_destroy(master); +} + +/* protocol helper struct */ +static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE, + "gre", + gre_pkt_to_tuple, + gre_invert_tuple, + gre_print_tuple, + gre_print_conntrack, + gre_packet, + gre_new, + gre_destroy, + NULL, + THIS_MODULE }; + +/* ip_conntrack_proto_gre initialization */ +static int __init init(void) +{ + int retcode; + + if ((retcode = ip_conntrack_protocol_register(&gre))) { + printk(KERN_ERR "Unable to register conntrack protocol " + "helper for gre: %d\n", retcode); + return -EIO; + } + + return 0; +} + +static void __exit fini(void) +{ + struct list_head *pos, *n; + + /* delete all keymap entries */ + WRITE_LOCK(&ip_ct_gre_lock); + list_for_each_safe(pos, n, &gre_keymap_list) { + DEBUGP("deleting keymap %p at module unload time\n", pos); + list_del(pos); + kfree(pos); + } + WRITE_UNLOCK(&ip_ct_gre_lock); + + ip_conntrack_protocol_unregister(&gre); +} + +EXPORT_SYMBOL(ip_ct_gre_keymap_add); +EXPORT_SYMBOL(ip_ct_gre_keymap_change); +EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_quake3.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_quake3.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_quake3.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_quake3.c 2003-12-10 23:14:06.244005464 +0100 @@ -0,0 +1,156 @@ +/* Quake3 extension for IP connection tracking + * (C) 2002 by Filip Sneppe + * based on ip_conntrack_ftp.c and ip_conntrack_tftp.c + * + * ip_conntrack_quake3.c v0.04 2002-08-31 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_conntrack_quake3.o ports=port1,port2,...port + * + * please give the ports of all Quake3 master servers You wish to + * connect to. If you don't specify ports, the default will be UDP + * port 27950. + * + * Thanks to the Ethereal folks for their analysis of the Quake3 protocol. + */ + +#include +#include +#include + +#include +#include +#include +#include + +struct module *ip_conntrack_quake3 = THIS_MODULE; + +MODULE_AUTHOR("Filip Sneppe "); +MODULE_DESCRIPTION("Netfilter connection tracking module for Quake III Arena"); +MODULE_LICENSE("GPL"); + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_c = 0; +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of Quake III master servers"); +#endif + +/* Quake3 master server reply will add > 100 expectations per reply packet; when + doing lots of printk's, klogd may not be able to read /proc/kmsg fast enough */ +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +struct quake3_search quake3s_conntrack = { "****", "getserversResponse", sizeof("getserversResponse") - 1 }; + +static int quake3_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct udphdr *udph = (void *)iph + iph->ihl * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_expect exp; + int i; + + /* Until there's been traffic both ways, don't look in packets. note: it's UDP ! */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_IS_REPLY) { + DEBUGP("ip_conntrack_quake3: not ok ! Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } else { DEBUGP("ip_conntrack_quake3: it's ok ! Conntrackinfo = %u\n", ctinfo); } + + if (strnicmp((const char *)udph + 12, quake3s_conntrack.pattern, quake3s_conntrack.plen) == 0) { + for(i=31; /* 8 bytes UDP hdr, 4 bytes filler, 18 bytes "getserversResponse", 1 byte "\" */ + i+6 < ntohs(udph->len); + i+=7) { + DEBUGP("ip_conntrack_quake3: adding server at offset %u/%u %u.%u.%u.%u:%u\n", + i, ntohs(udph->len), + NIPQUAD( (u_int32_t) *( (u_int32_t *)( (int)udph + i ) ) ), + ntohs((__u16) *( (__u16 *)( (int)udph + i + 4 ) ) ) ); + + memset(&exp, 0, sizeof(exp)); + + exp.tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, + { (u_int32_t) *((u_int32_t *)((int)udph + i)), + { .udp = { (__u16) *((__u16 *)((int)udph+i+4)) } }, + IPPROTO_UDP } } + ); + exp.mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 0xFFFF }}); + exp.expectfn = NULL; + + ip_conntrack_expect_related(ct, &exp); + } + + } + + return(NF_ACCEPT); +} + +static struct ip_conntrack_helper quake3[MAX_PORTS]; +static char quake3_names[MAX_PORTS][13]; /* quake3-65535 */ + +static void fini(void) +{ + int i; + + for(i = 0 ; (i < ports_c); i++) { + DEBUGP("ip_conntrack_quake3: unregistering helper for port %d\n", + ports[i]); + ip_conntrack_helper_unregister(&quake3[i]); + } +} + +static int __init init(void) +{ + int i, ret; + char *tmpname; + + if(!ports[0]) + ports[0]=QUAKE3_MASTER_PORT; + + for(i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { + /* Create helper structure */ + memset(&quake3[i], 0, sizeof(struct ip_conntrack_helper)); + + quake3[i].tuple.dst.protonum = IPPROTO_UDP; + quake3[i].tuple.src.u.udp.port = htons(ports[i]); + quake3[i].mask.dst.protonum = 0xFFFF; + quake3[i].mask.src.u.udp.port = 0xFFFF; + quake3[i].help = quake3_help; + quake3[i].me = THIS_MODULE; + + tmpname = &quake3_names[i][0]; + if (ports[i] == QUAKE3_MASTER_PORT) + sprintf(tmpname, "quake3"); + else + sprintf(tmpname, "quake3-%d", i); + quake3[i].name = tmpname; + + DEBUGP("ip_conntrack_quake3: registering helper for port %d\n", + ports[i]); + + ret=ip_conntrack_helper_register(&quake3[i]); + if(ret) { + fini(); + return(ret); + } + ports_c++; + } + + return(0); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 2003-12-10 23:14:10.153411144 +0100 @@ -0,0 +1,508 @@ +/* RPC extension for IP (TCP) connection tracking, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original rpc tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002,2003 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ip_conntrack_rpc_tpc.c,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_conntrack_rpc_tcp.o ports=port1,port2,...port + * + * Please give the ports of all RPC servers you wish to connect to. + * If you don't specify ports, the default will be port 111. + ** + * Note to all: + * + * RPCs should not be exposed to the internet - ask the Pentagon; + * + * "The unidentified crackers pleaded guilty in July to charges + * of juvenile delinquency stemming from a string of Pentagon + * network intrusions in February. + * + * The youths, going by the names TooShort and Makaveli, used + * a common server security hole to break in, according to + * Dane Jasper, owner of the California Internet service + * provider, Sonic. They used the hole, known as the 'statd' + * exploit, to attempt more than 800 break-ins, Jasper said." + * + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html + ** + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers"); +#endif + +MODULE_AUTHOR("Marcelo Barbosa Lima "); +MODULE_DESCRIPTION("RPC TCP connection tracking module"); +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_tcp: " \ + format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +DECLARE_RWLOCK(ipct_rpc_tcp_lock); +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_rpc_tcp_lock) +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_rpc_tcp_lock) +#include + +/* For future conections RPC, using client's cache bindings + * I'll use ip_conntrack_lock to lock these lists */ + +LIST_HEAD(request_p_list_tcp); + + +static void delete_request_p(unsigned long request_p_ul) +{ + struct request_p *p = (void *)request_p_ul; + + WRITE_LOCK(&ipct_rpc_tcp_lock); + LIST_DELETE(&request_p_list_tcp, p); + WRITE_UNLOCK(&ipct_rpc_tcp_lock); + kfree(p); + return; +} + + +static void req_cl(struct request_p * r) +{ + WRITE_LOCK(&ipct_rpc_tcp_lock); + del_timer(&r->timeout); + LIST_DELETE(&request_p_list_tcp, r); + WRITE_UNLOCK(&ipct_rpc_tcp_lock); + kfree(r); + return; +} + + +static void clean_request(struct list_head *list) +{ + struct list_head *first = list->prev; + struct list_head *temp = list->next; + struct list_head *aux; + + if (list_empty(list)) + return; + + while (first != temp) { + aux = temp->next; + req_cl((struct request_p *)temp); + temp = aux; + } + req_cl((struct request_p *)temp); + return; +} + + +static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip, + u_int16_t port) +{ + struct request_p *req_p; + + /* Verifies if entry already exists */ + WRITE_LOCK(&ipct_rpc_tcp_lock); + req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp, + struct request_p *, xid, ip, port); + + if (req_p) { + /* Refresh timeout */ + if (del_timer(&req_p->timeout)) { + req_p->timeout.expires = jiffies + EXP; + add_timer(&req_p->timeout); + } + WRITE_UNLOCK(&ipct_rpc_tcp_lock); + return; + + } + WRITE_UNLOCK(&ipct_rpc_tcp_lock); + + /* Allocate new request_p */ + req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC); + if (!req_p) { + DEBUGP("can't allocate request_p\n"); + return; + } + *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, + { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p, + NULL }}); + + /* Initialize timer */ + init_timer(&req_p->timeout); + req_p->timeout.function = delete_request_p; + add_timer(&req_p->timeout); + + /* Put in list */ + WRITE_LOCK(&ipct_rpc_tcp_lock); + list_prepend(&request_p_list_tcp, req_p); + WRITE_UNLOCK(&ipct_rpc_tcp_lock); + return; + +} + + +static int check_rpc_packet(const u_int32_t *data, + int dir, struct ip_conntrack *ct, + struct list_head request_p_list) +{ + struct request_p *req_p; + u_int32_t xid; + struct ip_conntrack_expect expect, *exp = &expect; + + /* Translstion's buffer for XDR */ + u_int16_t port_buf; + + + /* Get XID */ + xid = *data; + + /* This does sanity checking on RPC payloads, + * and permits only the RPC "get port" (3) + * in authorised procedures in client + * communications with the portmapper. + */ + + /* perform direction dependant RPC work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + data += 5; + + /* Get RPC requestor */ + if (IXDR_GET_INT32(data) != 3) { + DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n"); + return NF_ACCEPT; + } + DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n"); + + data++; + + /* Jump Credentials and Verfifier */ + data += IXDR_GET_INT32(data) + 2; + data += IXDR_GET_INT32(data) + 2; + + /* Get RPC procedure */ + DEBUGP("RPC packet contains procedure request [%u]. [cont]\n", + (unsigned int)IXDR_GET_INT32(data)); + + /* Get RPC protocol and store against client parameters */ + data = data + 2; + alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip, + ct->tuplehash[dir].tuple.src.u.all); + + DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n", + xid, IXDR_GET_INT32(data), + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + ntohs(ct->tuplehash[dir].tuple.src.u.all)); + + DEBUGP("allocated RPC request for protocol %u. [done]\n", + (unsigned int)IXDR_GET_INT32(data)); + + } else { + + /* Check for returning packet's stored counterpart */ + req_p = LIST_FIND(&request_p_list_tcp, request_p_cmp, + struct request_p *, xid, + ct->tuplehash[!dir].tuple.src.ip, + ct->tuplehash[!dir].tuple.src.u.all); + + /* Drop unexpected packets */ + if (!req_p) { + DEBUGP("packet is not expected. [skip]\n"); + return NF_ACCEPT; + } + + /* Verifies if packet is really an RPC reply packet */ + data = data++; + if (IXDR_GET_INT32(data) != 1) { + DEBUGP("packet is not a valid RPC reply. [skip]\n"); + return NF_ACCEPT; + } + + /* Is status accept? */ + data++; + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an RPC accept. [skip]\n"); + return NF_ACCEPT; + } + + /* Get Verifier length. Jump verifier */ + data++; + data = data + IXDR_GET_INT32(data) + 2; + + /* Is accpet status "success"? */ + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an RPC accept status of success. [skip]\n"); + return NF_ACCEPT; + } + + /* Get server port number */ + data++; + port_buf = (u_int16_t) IXDR_GET_INT32(data); + + /* If a packet has made it this far then it deserves an + * expectation ... if port == 0, then this service is + * not going to be registered. + */ + if (port_buf) { + DEBUGP("port found: %u\n", port_buf); + + memset(&expect, 0, sizeof(expect)); + + /* Watch out, Radioactive-Man! */ + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; + exp->mask.src.ip = 0xffffffff; + exp->mask.dst.ip = 0xffffffff; + + switch (req_p->proto) { + case IPPROTO_UDP: + exp->tuple.src.u.udp.port = 0; + exp->tuple.dst.u.udp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_UDP; + exp->mask.src.u.udp.port = 0; + exp->mask.dst.u.udp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + + case IPPROTO_TCP: + exp->tuple.src.u.tcp.port = 0; + exp->tuple.dst.u.tcp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_TCP; + exp->mask.src.u.tcp.port = 0; + exp->mask.dst.u.tcp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + } + exp->expectfn = NULL; + + ip_conntrack_expect_related(ct, &expect); + + DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n", + NIPQUAD(exp->tuple.src.ip), + NIPQUAD(exp->tuple.dst.ip), + port_buf, req_p->proto); + + DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n", + NIPQUAD(exp->mask.src.ip), + NIPQUAD(exp->mask.dst.ip), + exp->mask.dst.protonum); + + } + + req_cl(req_p); + + DEBUGP("packet evaluated. [expect]\n"); + return NF_ACCEPT; + } + + return NF_ACCEPT; + +} + + +/* RPC TCP helper */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + const u_int32_t *data = (const u_int32_t *)tcph + tcph->doff; + size_t tcplen = len - iph->ihl * 4; + + int dir = CTINFO2DIR(ctinfo); + int crp_ret; + + + DEBUGP("new packet to evaluate ..\n"); + + /* This works for packets like handshake packets, ignore */ + if (len == ((tcph->doff + iph->ihl) * 4)) { + DEBUGP("packet has no data (may still be handshaking). [skip]\n"); + return NF_ACCEPT; + } + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo); + DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n"); + DEBUGP("packet is not yet part of a two way stream. [skip]\n"); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("TCP header length is; tcplen=%u ..\n", (unsigned) tcplen); + DEBUGP("packet does not contain a complete TCP header. [skip]\n"); + return NF_ACCEPT; + } + + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP("csum; %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + DEBUGP("[note: failure to get past this error may indicate source routing]\n"); + DEBUGP("packet contains a bad checksum. [skip]\n"); + return NF_ACCEPT; + } + + /* perform direction dependant protocol work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + DEBUGP("packet is from the initiator. [cont]\n"); + + /* Tests if packet len is ok */ + if ((tcplen - (tcph->doff * 4)) != 60) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + + } else { + + DEBUGP("packet is from the receiver. [cont]\n"); + + /* Tests if packet len is ok */ + if ((tcplen - (tcph->doff * 4)) != 32) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + } + + /* Get to the data */ + data++; + + /* Check the RPC data */ + crp_ret = check_rpc_packet(data, dir, ct, request_p_list_tcp); + + return crp_ret; + +} + + +static struct ip_conntrack_helper rpc_helpers[MAX_PORTS]; + +static void fini(void); + + +static int __init init(void) +{ + int port, ret; + static char name[10]; + + + /* If no port given, default to standard RPC port */ + if (ports[0] == 0) + ports[0] = RPC_PORT; + + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { + memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper)); + + if (ports[port] == RPC_PORT) + sprintf(name, "rpc"); + else + sprintf(name, "rpc-%d", port); + + rpc_helpers[port].name = name; + rpc_helpers[port].me = THIS_MODULE; + rpc_helpers[port].max_expected = 1; + rpc_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; + rpc_helpers[port].timeout = 0; + + rpc_helpers[port].tuple.dst.protonum = IPPROTO_TCP; + rpc_helpers[port].mask.dst.protonum = 0xffff; + + /* RPC can come from ports 0:65535 to ports[port] (111) */ + rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]); + rpc_helpers[port].mask.src.u.udp.port = htons(0xffff); + rpc_helpers[port].mask.dst.u.udp.port = htons(0x0); + + rpc_helpers[port].help = help; + + DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]); + DEBUGP("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(rpc_helpers[port].tuple.dst.ip), + ntohs(rpc_helpers[port].tuple.dst.u.tcp.port), + NIPQUAD(rpc_helpers[port].tuple.src.ip), + ntohs(rpc_helpers[port].tuple.src.u.tcp.port)); + DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(rpc_helpers[port].mask.dst.ip), + ntohs(rpc_helpers[port].mask.dst.u.tcp.port), + NIPQUAD(rpc_helpers[port].mask.src.ip), + ntohs(rpc_helpers[port].mask.src.u.tcp.port)); + + ret = ip_conntrack_helper_register(&rpc_helpers[port]); + + if (ret) { + printk("ERROR registering port %d\n", + ports[port]); + fini(); + return -EBUSY; + } + ports_n_c++; + } + return 0; +} + + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void fini(void) +{ + int port; + + DEBUGP("cleaning request list\n"); + clean_request(&request_p_list_tcp); + + for (port = 0; (port < ports_n_c) && ports[port]; port++) { + DEBUGP("unregistering port %d\n", ports[port]); + ip_conntrack_helper_unregister(&rpc_helpers[port]); + } +} + + +module_init(init); +module_exit(fini); + +struct module *ip_conntrack_rpc_tcp = THIS_MODULE; +EXPORT_SYMBOL(request_p_list_tcp); +EXPORT_SYMBOL(ip_conntrack_rpc_tcp); +EXPORT_SYMBOL(ipct_rpc_tcp_lock); + diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rpc_udp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 2003-12-10 23:14:10.154410992 +0100 @@ -0,0 +1,503 @@ +/* RPC extension for IP (UDP) connection tracking, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original rpc tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002,2003 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ip_conntrack_rpc_udp.c,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_conntrack_rpc_udp.o ports=port1,port2,...port + * + * Please give the ports of all RPC servers you wish to connect to. + * If you don't specify ports, the default will be port 111. + ** + * Note to all: + * + * RPCs should not be exposed to the internet - ask the Pentagon; + * + * "The unidentified crackers pleaded guilty in July to charges + * of juvenile delinquency stemming from a string of Pentagon + * network intrusions in February. + * + * The youths, going by the names TooShort and Makaveli, used + * a common server security hole to break in, according to + * Dane Jasper, owner of the California Internet service + * provider, Sonic. They used the hole, known as the 'statd' + * exploit, to attempt more than 800 break-ins, Jasper said." + * + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html + ** + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers"); +#endif + +MODULE_AUTHOR("Marcelo Barbosa Lima "); +MODULE_DESCRIPTION("RPC UDP connection tracking module"); +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rpc_udp: " \ + format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +DECLARE_RWLOCK(ipct_rpc_udp_lock); +#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ipct_rpc_udp_lock) +#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ipct_rpc_udp_lock) +#include + +/* For future conections RPC, using client's cache bindings + * I'll use ip_conntrack_lock to lock these lists */ + +LIST_HEAD(request_p_list_udp); + + +static void delete_request_p(unsigned long request_p_ul) +{ + struct request_p *p = (void *)request_p_ul; + + WRITE_LOCK(&ipct_rpc_udp_lock); + LIST_DELETE(&request_p_list_udp, p); + WRITE_UNLOCK(&ipct_rpc_udp_lock); + kfree(p); + return; +} + + +static void req_cl(struct request_p * r) +{ + WRITE_LOCK(&ipct_rpc_udp_lock); + del_timer(&r->timeout); + LIST_DELETE(&request_p_list_udp, r); + WRITE_UNLOCK(&ipct_rpc_udp_lock); + kfree(r); + return; +} + + +static void clean_request(struct list_head *list) +{ + struct list_head *first = list->prev; + struct list_head *temp = list->next; + struct list_head *aux; + + if (list_empty(list)) + return; + + while (first != temp) { + aux = temp->next; + req_cl((struct request_p *)temp); + temp = aux; + } + req_cl((struct request_p *)temp); + return; +} + + +static void alloc_request_p(u_int32_t xid, u_int16_t proto, u_int32_t ip, + u_int16_t port) +{ + struct request_p *req_p; + + /* Verifies if entry already exists */ + WRITE_LOCK(&ipct_rpc_udp_lock); + req_p = LIST_FIND(&request_p_list_udp, request_p_cmp, + struct request_p *, xid, ip, port); + + if (req_p) { + /* Refresh timeout */ + if (del_timer(&req_p->timeout)) { + req_p->timeout.expires = jiffies + EXP; + add_timer(&req_p->timeout); + } + WRITE_UNLOCK(&ipct_rpc_udp_lock); + return; + + } + WRITE_UNLOCK(&ipct_rpc_udp_lock); + + /* Allocate new request_p */ + req_p = (struct request_p *) kmalloc(sizeof(struct request_p), GFP_ATOMIC); + if (!req_p) { + DEBUGP("can't allocate request_p\n"); + return; + } + *req_p = ((struct request_p) {{ NULL, NULL }, xid, ip, port, proto, + { { NULL, NULL }, jiffies + EXP, (unsigned long)req_p, + NULL }}); + + /* Initialize timer */ + init_timer(&req_p->timeout); + req_p->timeout.function = delete_request_p; + add_timer(&req_p->timeout); + + /* Put in list */ + WRITE_LOCK(&ipct_rpc_udp_lock); + list_prepend(&request_p_list_udp, req_p); + WRITE_UNLOCK(&ipct_rpc_udp_lock); + return; + +} + + +static int check_rpc_packet(const u_int32_t *data, + int dir, struct ip_conntrack *ct, + struct list_head request_p_list) +{ + struct request_p *req_p; + u_int32_t xid; + struct ip_conntrack_expect expect, *exp = &expect; + + /* Translstion's buffer for XDR */ + u_int16_t port_buf; + + + /* Get XID */ + xid = *data; + + /* This does sanity checking on RPC payloads, + * and permits only the RPC "get port" (3) + * in authorised procedures in client + * communications with the portmapper. + */ + + /* perform direction dependant RPC work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + data += 5; + + /* Get RPC requestor */ + if (IXDR_GET_INT32(data) != 3) { + DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n"); + return NF_ACCEPT; + } + DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n"); + + data++; + + /* Jump Credentials and Verfifier */ + data = data + IXDR_GET_INT32(data) + 2; + data = data + IXDR_GET_INT32(data) + 2; + + /* Get RPC procedure */ + DEBUGP("RPC packet contains procedure request [%u]. [cont]\n", + (unsigned int)IXDR_GET_INT32(data)); + + /* Get RPC protocol and store against client parameters */ + data = data + 2; + alloc_request_p(xid, IXDR_GET_INT32(data), ct->tuplehash[dir].tuple.src.ip, + ct->tuplehash[dir].tuple.src.u.all); + + DEBUGP("allocated RPC req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n", + xid, IXDR_GET_INT32(data), + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + ntohs(ct->tuplehash[dir].tuple.src.u.all)); + + DEBUGP("allocated RPC request for protocol %u. [done]\n", + (unsigned int)IXDR_GET_INT32(data)); + + } else { + + /* Check for returning packet's stored counterpart */ + req_p = LIST_FIND(&request_p_list_udp, request_p_cmp, + struct request_p *, xid, + ct->tuplehash[!dir].tuple.src.ip, + ct->tuplehash[!dir].tuple.src.u.all); + + /* Drop unexpected packets */ + if (!req_p) { + DEBUGP("packet is not expected. [skip]\n"); + return NF_ACCEPT; + } + + /* Verifies if packet is really an RPC reply packet */ + data = data++; + if (IXDR_GET_INT32(data) != 1) { + DEBUGP("packet is not a valid RPC reply. [skip]\n"); + return NF_ACCEPT; + } + + /* Is status accept? */ + data++; + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an RPC accept. [skip]\n"); + return NF_ACCEPT; + } + + /* Get Verifier length. Jump verifier */ + data++; + data = data + IXDR_GET_INT32(data) + 2; + + /* Is accpet status "success"? */ + if (IXDR_GET_INT32(data)) { + DEBUGP("packet is not an RPC accept status of success. [skip]\n"); + return NF_ACCEPT; + } + + /* Get server port number */ + data++; + port_buf = (u_int16_t) IXDR_GET_INT32(data); + + /* If a packet has made it this far then it deserves an + * expectation ... if port == 0, then this service is + * not going to be registered. + */ + if (port_buf) { + DEBUGP("port found: %u\n", port_buf); + + memset(&expect, 0, sizeof(expect)); + + /* Watch out, Radioactive-Man! */ + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; + exp->mask.src.ip = 0xffffffff; + exp->mask.dst.ip = 0xffffffff; + + switch (req_p->proto) { + case IPPROTO_UDP: + exp->tuple.src.u.udp.port = 0; + exp->tuple.dst.u.udp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_UDP; + exp->mask.src.u.udp.port = 0; + exp->mask.dst.u.udp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + + case IPPROTO_TCP: + exp->tuple.src.u.tcp.port = 0; + exp->tuple.dst.u.tcp.port = htons(port_buf); + exp->tuple.dst.protonum = IPPROTO_TCP; + exp->mask.src.u.tcp.port = 0; + exp->mask.dst.u.tcp.port = htons(0xffff); + exp->mask.dst.protonum = 0xffff; + break; + } + exp->expectfn = NULL; + + ip_conntrack_expect_related(ct, &expect); + + DEBUGP("expect related ip %u.%u.%u.%u:0-%u.%u.%u.%u:%u proto=%u\n", + NIPQUAD(exp->tuple.src.ip), + NIPQUAD(exp->tuple.dst.ip), + port_buf, req_p->proto); + + DEBUGP("expect related mask %u.%u.%u.%u:0-%u.%u.%u.%u:65535 proto=%u\n", + NIPQUAD(exp->mask.src.ip), + NIPQUAD(exp->mask.dst.ip), + exp->mask.dst.protonum); + + } + + req_cl(req_p); + + DEBUGP("packet evaluated. [expect]\n"); + return NF_ACCEPT; + } + + return NF_ACCEPT; + +} + + +/* RPC UDP helper */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + struct udphdr *udph = (void *) iph + iph->ihl * 4; + const u_int32_t *data = (const u_int32_t *)udph + 2; + size_t udplen = len - iph->ihl * 4; + int dir = CTINFO2DIR(ctinfo); + int crp_ret; + + /* Checksum */ + const u_int16_t *chsm = (const u_int16_t *)udph + 3; + + + DEBUGP("new packet to evaluate ..\n"); + + /* Not whole UDP header? */ + if (udplen < sizeof(struct udphdr)) { + DEBUGP("UDP header length is; udplen=%u ..\n", (unsigned) udplen); + DEBUGP("packet does not contain a complete UDP header. [skip]\n"); + return NF_ACCEPT; + } + + /* FIXME: Source route IP option packets --RR */ + if (*chsm) { + if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, + csum_partial((char *)udph, udplen, 0))) { + DEBUGP("[note: failure to get past this error may indicate source routing]\n"); + DEBUGP("packet contains a bad checksum. [skip]\n"); + return NF_ACCEPT; + } + } + + /* perform direction dependant protocol work */ + if (dir == IP_CT_DIR_ORIGINAL) { + + DEBUGP("packet is from the initiator. [cont]\n"); + + /* Tests if packet len is ok */ + if ((udplen - sizeof(struct udphdr)) != 56) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + + } else { + + DEBUGP("packet is from the receiver. [cont]\n"); + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("connection tracking state is; ctinfo=%u ..\n", ctinfo); + DEBUGP("[note: failure to get past this error may indicate asymmetric routing]\n"); + DEBUGP("packet is not yet part of a two way stream. [skip]\n"); + return NF_ACCEPT; + } + + /* Tests if packet len is ok */ + if ((udplen - sizeof(struct udphdr)) != 28) { + DEBUGP("packet length is not correct. [skip]\n"); + return NF_ACCEPT; + } + + } + + /* Get to the data */ + /* udp *data == *correct */ + + /* Check the RPC data */ + crp_ret = check_rpc_packet(data, dir, ct, request_p_list_udp); + + return crp_ret; + +} + + +static struct ip_conntrack_helper rpc_helpers[MAX_PORTS]; + +static void fini(void); + + +static int __init init(void) +{ + int port, ret; + static char name[10]; + + + /* If no port given, default to standard RPC port */ + if (ports[0] == 0) + ports[0] = RPC_PORT; + + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { + memset(&rpc_helpers[port], 0, sizeof(struct ip_conntrack_helper)); + + if (ports[port] == RPC_PORT) + sprintf(name, "rpc"); + else + sprintf(name, "rpc-%d", port); + + rpc_helpers[port].name = name; + rpc_helpers[port].me = THIS_MODULE; + rpc_helpers[port].max_expected = 1; + rpc_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; + rpc_helpers[port].timeout = 0; + + rpc_helpers[port].tuple.dst.protonum = IPPROTO_UDP; + rpc_helpers[port].mask.dst.protonum = 0xffff; + + /* RPC can come from ports 0:65535 to ports[port] (111) */ + rpc_helpers[port].tuple.src.u.udp.port = htons(ports[port]); + rpc_helpers[port].mask.src.u.udp.port = htons(0xffff); + rpc_helpers[port].mask.dst.u.udp.port = htons(0x0); + + rpc_helpers[port].help = help; + + DEBUGP("registering helper for port #%d: %d/UDP\n", port, ports[port]); + DEBUGP("helper match ip %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(rpc_helpers[port].tuple.dst.ip), + ntohs(rpc_helpers[port].tuple.dst.u.udp.port), + NIPQUAD(rpc_helpers[port].tuple.src.ip), + ntohs(rpc_helpers[port].tuple.src.u.udp.port)); + DEBUGP("helper match mask %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(rpc_helpers[port].mask.dst.ip), + ntohs(rpc_helpers[port].mask.dst.u.udp.port), + NIPQUAD(rpc_helpers[port].mask.src.ip), + ntohs(rpc_helpers[port].mask.src.u.udp.port)); + + ret = ip_conntrack_helper_register(&rpc_helpers[port]); + + if (ret) { + printk("ERROR registering port %d\n", + ports[port]); + fini(); + return -EBUSY; + } + ports_n_c++; + } + return 0; +} + + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void fini(void) +{ + int port; + + DEBUGP("cleaning request list\n"); + clean_request(&request_p_list_udp); + + for (port = 0; (port < ports_n_c) && ports[port]; port++) { + DEBUGP("unregistering port %d\n", ports[port]); + ip_conntrack_helper_unregister(&rpc_helpers[port]); + } +} + + +module_init(init); +module_exit(fini); + +struct module *ip_conntrack_rpc_udp = THIS_MODULE; +EXPORT_SYMBOL(request_p_list_udp); +EXPORT_SYMBOL(ip_conntrack_rpc_udp); +EXPORT_SYMBOL(ipct_rpc_udp_lock); + diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rsh.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rsh.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rsh.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rsh.c 2003-12-10 23:14:11.557197736 +0100 @@ -0,0 +1,331 @@ +/* RSH extension for IP connection tracking, Version 1.0 + * (C) 2002 by Ian (Larry) Latter + * based on HW's ip_conntrack_irc.c + * + * ip_conntrack_rsh.c,v 1.0 2002/07/17 14:49:26 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_conntrack_rsh.o ports=port1,port2,...port + * + * please give the ports of all RSH servers You wish to connect to. + * If You don't specify ports, the default will be port 514 + ** + * Note to all: + * RSH blows ... you should use SSH (openssh.org) to replace it, + * unfortunately I babysit some sysadmins that won't migrate + * their legacy crap, in our second tier. + */ + + +/* + * Some docco ripped from the net to teach me all there is to know about + * RSH, in 16.5 seconds (ie, all of the non-netfilter docco used to write + * this module). + * + * I have no idea what "unix rshd man pages" these guys have .. but that + * is some pretty detailed docco! + ** + * + * 4. Of the rsh protocol. + * ----------------------- + * + * The rshd listens on TCP port #514. The following info is from the unix + * rshd man pages : + * + * "Service Request Protocol + * + * When the rshd daemon receives a service request, it initiates the + * following protocol: + * + * 1. The rshd daemon checks the source port number for the request. + * If the port number is not in the range 0 through 1023, the rshd daemon + * terminates the connection. + * + * 2. The rshd daemon reads characters from the socket up to a null byte. + * The string read is interpreted as an ASCII number (base 10). If this + * number is nonzero, the rshd daemon interprets it as the port number + * of a secondary stream to be used as standard error. A second connection + * is created to the specified port on the client host. The source port + * on the local host is in the range 0 through 1023. + * + * 3. The rshd daemon uses the source address of the initial connection + * request to determine the name of the client host. If the name cannot + * be determined, the rshd daemon uses the dotted decimal representation + * of the client host's address. + * + * 4. The rshd daemon retrieves the following information from the initial + * socket: + * + * * A null-terminated string of at most 16 bytes interpreted as + * the user name of the user on the client host. + * + * * A null-terminated string of at most 16 bytes interpreted as + * the user name to be used on the local server host. + * + * * Another null-terminated string interpreted as a command line + * to be passed to a shell on the local server host. + * + * 5. The rshd daemon attempts to validate the user using the following steps: + * + * a. The rshd daemon looks up the local user name in the /etc/passwd + * file and tries to switch to the home directory (using the chdir + * subroutine). If either the lookup or the directory change fails, + * the rshd daemon terminates the connection. + * + * b. If the local user ID is a nonzero value, the rshd daemon searches + * the /etc/hosts.equiv file to see if the name of the client + * workstation is listed. If the client workstation is listed as an + * equivalent host, the rshd daemon validates the user. + * + * c. If the $HOME/.rhosts file exists, the rshd daemon tries to + * authenticate the user by checking the .rhosts file. + * + * d. If either the $HOME/.rhosts authentication fails or the + * client host is not an equivalent host, the rshd daemon + * terminates the connection. + * + * 6. Once rshd validates the user, the rshd daemon returns a null byte + * on the initial connection and passes the command line to the user's + * local login shell. The shell then inherits the network connections + * established by the rshd daemon." + * + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +MODULE_AUTHOR("Ian (Larry) Latter "); +MODULE_DESCRIPTION("RSH connection tracking module"); +MODULE_LICENSE("GPL"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of RSH servers"); +#endif + +DECLARE_LOCK(ip_rsh_lock); +struct module *ip_conntrack_rsh = THIS_MODULE; + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ip_conntrack_rsh: " \ + format, ## args) +#else +#define DEBUGP(format, args...) +#endif + + + +/* FIXME: This should be in userspace. Later. */ +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + const char *data = (const char *) tcph + tcph->doff * 4; + u_int32_t tcplen = len - iph->ihl * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_expect expect, *exp = &expect; + struct ip_ct_rsh_expect *exp_rsh_info = &exp->help.exp_rsh_info; + u_int16_t port; + int maxoctet; + + /* note that "maxoctet" is used to maintain sanity (8 was the + * original array size used in rshd/glibc) -- is there a + * vulnerability in rshd.c in the looped port *= 10? + */ + + + DEBUGP("entered\n"); + + /* bail if packet is not from RSH client */ + if (dir == IP_CT_DIR_REPLY) + return NF_ACCEPT; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { + DEBUGP("tcplen = %u\n", (unsigned) tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *) tcph, tcplen, 0))) { + DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + /* find the rsh stderr port */ + maxoctet = 4; + port = 0; + for ( ; *data != 0 && maxoctet != 0; data++, maxoctet--) { + if (*data < 0) + return(1); + if (*data == 0) + break; + if (*data < 48 || *data > 57) { + DEBUGP("these aren't the packets you're looking for ..\n"); + return NF_ACCEPT; + } + port = port * 10 + ( *data - 48 ); + } + + /* dont relate sessions that try to expose the client */ + DEBUGP("found port %u\n", port); + if (port > 1023) { + DEBUGP("skipping, expected port size is greater than 1023!\n"); + return NF_ACCEPT; + } + + + LOCK_BH(&ip_rsh_lock); + + /* new(,related) connection is; + * reply + dst (uint)port + src port (0:1023) + */ + memset(&expect, 0, sizeof(expect)); + + /* save some discovered data, in case someone ever wants to write + * a NAT module for this bastard .. + */ + exp_rsh_info->port = port; + + DEBUGP("wrote info port=%u\n", exp_rsh_info->port); + + + /* Watch out, Radioactive-Man! */ + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; + exp->tuple.src.u.tcp.port = 0; + exp->tuple.dst.u.tcp.port = htons(exp_rsh_info->port); + exp->tuple.dst.protonum = IPPROTO_TCP; + + exp->mask.src.ip = 0xffffffff; + exp->mask.dst.ip = 0xffffffff; + + exp->mask.src.u.tcp.port = htons(0xfc00); + exp->mask.dst.u.tcp.port = htons(0xfc00); + exp->mask.dst.protonum = 0xffff; + + exp->expectfn = NULL; + + ip_conntrack_expect_related(ct, &expect); + + DEBUGP("expect related ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", + NIPQUAD(exp->tuple.src.ip), + ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), + ntohs(exp->tuple.dst.u.tcp.port)); + + DEBUGP("expect related mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", + NIPQUAD(exp->mask.src.ip), + ntohs(exp->mask.src.u.tcp.port), + NIPQUAD(exp->mask.dst.ip), + ntohs(exp->mask.dst.u.tcp.port)); + UNLOCK_BH(&ip_rsh_lock); + + return NF_ACCEPT; +} + +static struct ip_conntrack_helper rsh_helpers[MAX_PORTS]; + +static void fini(void); + +static int __init init(void) +{ + int port, ret; + static char name[10]; + + + /* If no port given, default to standard RSH port */ + if (ports[0] == 0) + ports[0] = RSH_PORT; + + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { + memset(&rsh_helpers[port], 0, sizeof(struct ip_conntrack_helper)); + + if (ports[port] == RSH_PORT) + sprintf(name, "rsh"); + else + sprintf(name, "rsh-%d", port); + + rsh_helpers[port].name = name; + rsh_helpers[port].me = THIS_MODULE; + rsh_helpers[port].max_expected = 1; + rsh_helpers[port].flags = IP_CT_HELPER_F_REUSE_EXPECT; + rsh_helpers[port].timeout = 0; + + rsh_helpers[port].tuple.dst.protonum = IPPROTO_TCP; + rsh_helpers[port].mask.dst.protonum = 0xffff; + + /* RSH must come from ports 0:1023 to ports[port] (514) */ + rsh_helpers[port].tuple.src.u.tcp.port = htons(ports[port]); + rsh_helpers[port].mask.src.u.tcp.port = htons(0xfc00); + rsh_helpers[port].mask.dst.u.tcp.port = htons(0xfc00); + + rsh_helpers[port].help = help; + + DEBUGP("registering helper for port #%d: %d/TCP\n", port, ports[port]); + DEBUGP("helper match ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", + NIPQUAD(rsh_helpers[port].tuple.src.ip), + ntohs(rsh_helpers[port].tuple.src.u.tcp.port), + NIPQUAD(rsh_helpers[port].tuple.dst.ip), + ntohs(rsh_helpers[port].tuple.dst.u.tcp.port)); + DEBUGP("helper match mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", + NIPQUAD(rsh_helpers[port].mask.src.ip), + ntohs(rsh_helpers[port].mask.src.u.tcp.port), + NIPQUAD(rsh_helpers[port].mask.dst.ip), + ntohs(rsh_helpers[port].mask.dst.u.tcp.port)); + + ret = ip_conntrack_helper_register(&rsh_helpers[port]); + + if (ret) { + printk("ERROR registering port %d\n", + ports[port]); + fini(); + return -EBUSY; + } + ports_n_c++; + } + return 0; +} + +/* This function is intentionally _NOT_ defined as __exit, because + * it is needed by the init function */ +static void fini(void) +{ + int port; + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { + DEBUGP("unregistering port %d\n", ports[port]); + ip_conntrack_helper_unregister(&rsh_helpers[port]); + } +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rtsp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_rtsp.c 2003-12-10 23:14:12.891994816 +0100 @@ -0,0 +1,509 @@ +/* + * RTSP extension for IP connection tracking + * (C) 2003 by Tom Marshall + * based on ip_conntrack_irc.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_conntrack_rtsp.o ports=port1,port2,...port + * max_outstanding=n setup_timeout=secs + * + * If no ports are specified, the default will be port 554. + * + * With max_outstanding you can define the maximum number of not yet + * answered SETUP requests per RTSP session (default 8). + * With setup_timeout you can specify how long the system waits for + * an expected data channel (default 300 seconds). + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#define NF_NEED_STRNCASECMP +#define NF_NEED_STRTOU16 +#define NF_NEED_STRTOU32 +#define NF_NEED_NEXTLINE +#include +#define NF_NEED_MIME_NEXTLINE +#include + +#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */ + +#define INFOP(args...) printk(KERN_INFO __FILE__ ":" __FUNCTION__ ":" args) +#ifdef IP_NF_RTSP_DEBUG +#define DEBUGP(args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ ":" args) +#else +#define DEBUGP(args...) +#endif + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int num_ports = 0; +static int max_outstanding = 8; +static unsigned int setup_timeout = 300; + +MODULE_AUTHOR("Tom Marshall "); +MODULE_DESCRIPTION("RTSP connection tracking module"); +MODULE_LICENSE("GPL"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); +MODULE_PARM(max_outstanding, "i"); +MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session"); +MODULE_PARM(setup_timeout, "i"); +MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels"); +#endif + +DECLARE_LOCK(ip_rtsp_lock); +struct module* ip_conntrack_rtsp = THIS_MODULE; + +/* + * Max mappings we will allow for one RTSP connection (for RTP, the number + * of allocated ports is twice this value). Note that SMIL burns a lot of + * ports so keep this reasonably high. If this is too low, you will see a + * lot of "no free client map entries" messages. + */ +#define MAX_PORT_MAPS 16 + +/*** default port list was here in the masq code: 554, 3030, 4040 ***/ + +#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } + +/* + * Parse an RTSP packet. + * + * Returns zero if parsing failed. + * + * Parameters: + * IN ptcp tcp data pointer + * IN tcplen tcp data len + * IN/OUT ptcpoff points to current tcp offset + * OUT phdrsoff set to offset of rtsp headers + * OUT phdrslen set to length of rtsp headers + * OUT pcseqoff set to offset of CSeq header + * OUT pcseqlen set to length of CSeq header + */ +static int +rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, + uint* phdrsoff, uint* phdrslen, + uint* pcseqoff, uint* pcseqlen) +{ + uint entitylen = 0; + uint lineoff; + uint linelen; + + if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) + { + return 0; + } + + *phdrsoff = *ptcpoff; + while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) + { + if (linelen == 0) + { + if (entitylen > 0) + { + *ptcpoff += min(entitylen, tcplen - *ptcpoff); + } + break; + } + if (lineoff+linelen > tcplen) + { + INFOP("!! overrun !!\n"); + break; + } + + if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) + { + *pcseqoff = lineoff; + *pcseqlen = linelen; + } + if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) + { + uint off = lineoff+15; + SKIP_WSPACE(ptcp+lineoff, linelen, off); + nf_strtou32(ptcp+off, &entitylen); + } + } + *phdrslen = (*ptcpoff) - (*phdrsoff); + + return 1; +} + +/* + * Find lo/hi client ports (if any) in transport header + * In: + * ptcp, tcplen = packet + * tranoff, tranlen = buffer to search + * + * Out: + * pport_lo, pport_hi = lo/hi ports (host endian) + * + * Returns nonzero if any client ports found + * + * Note: it is valid (and expected) for the client to request multiple + * transports, so we need to parse the entire line. + */ +static int +rtsp_parse_transport(char* ptran, uint tranlen, + struct ip_ct_rtsp_expect* prtspexp) +{ + int rc = 0; + uint off = 0; + + if (tranlen < 10 || !iseol(ptran[tranlen-1]) || + nf_strncasecmp(ptran, "Transport:", 10) != 0) + { + INFOP("sanity check failed\n"); + return 0; + } + DEBUGP("tran='%.*s'\n", (int)tranlen, ptran); + off += 10; + SKIP_WSPACE(ptran, tranlen, off); + + /* Transport: tran;field;field=val,tran;field;field=val,... */ + while (off < tranlen) + { + const char* pparamend; + uint nextparamoff; + + pparamend = memchr(ptran+off, ',', tranlen-off); + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; + nextparamoff = pparamend-ptran; + + while (off < nextparamoff) + { + const char* pfieldend; + uint nextfieldoff; + + pfieldend = memchr(ptran+off, ';', nextparamoff-off); + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; + + if (strncmp(ptran+off, "client_port=", 12) == 0) + { + u_int16_t port; + uint numlen; + + off += 12; + numlen = nf_strtou16(ptran+off, &port); + off += numlen; + if (prtspexp->loport != 0 && prtspexp->loport != port) + { + DEBUGP("multiple ports found, port %hu ignored\n", port); + } + else + { + prtspexp->loport = prtspexp->hiport = port; + if (ptran[off] == '-') + { + off++; + numlen = nf_strtou16(ptran+off, &port); + off += numlen; + prtspexp->pbtype = pb_range; + prtspexp->hiport = port; + + // If we have a range, assume rtp: + // loport must be even, hiport must be loport+1 + if ((prtspexp->loport & 0x0001) != 0 || + prtspexp->hiport != prtspexp->loport+1) + { + DEBUGP("incorrect range: %hu-%hu, correcting\n", + prtspexp->loport, prtspexp->hiport); + prtspexp->loport &= 0xfffe; + prtspexp->hiport = prtspexp->loport+1; + } + } + else if (ptran[off] == '/') + { + off++; + numlen = nf_strtou16(ptran+off, &port); + off += numlen; + prtspexp->pbtype = pb_discon; + prtspexp->hiport = port; + } + rc = 1; + } + } + + /* + * Note we don't look for the destination parameter here. + * If we are using NAT, the NAT module will handle it. If not, + * and the client is sending packets elsewhere, the expectation + * will quietly time out. + */ + + off = nextfieldoff; + } + + off = nextparamoff; + } + + return rc; +} + +/*** conntrack functions ***/ + +/* outbound packet: client->server */ +static int +help_out(const struct iphdr* iph, size_t pktlen, + struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) +{ + int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */ + struct tcphdr* tcph = (void*)iph + iph->ihl * 4; + uint tcplen = pktlen - iph->ihl * 4; + char* pdata = (char*)tcph + tcph->doff * 4; + uint datalen = tcplen - tcph->doff * 4; + uint dataoff = 0; + + struct ip_conntrack_expect exp; + + while (dataoff < datalen) + { + uint cmdoff = dataoff; + uint hdrsoff = 0; + uint hdrslen = 0; + uint cseqoff = 0; + uint cseqlen = 0; + uint lineoff = 0; + uint linelen = 0; + uint off; + int rc; + + if (!rtsp_parse_message(pdata, datalen, &dataoff, + &hdrsoff, &hdrslen, + &cseqoff, &cseqlen)) + { + break; /* not a valid message */ + } + + if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) + { + continue; /* not a SETUP message */ + } + DEBUGP("found a setup message\n"); + + memset(&exp, 0, sizeof(exp)); + + off = 0; + while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off, + &lineoff, &linelen)) + { + if (linelen == 0) + { + break; + } + if (off > hdrsoff+hdrslen) + { + INFOP("!! overrun !!"); + break; + } + + if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0) + { + rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen, + &exp.help.exp_rtsp_info); + } + } + + if (exp.help.exp_rtsp_info.loport == 0) + { + DEBUGP("no udp transports found\n"); + continue; /* no udp transports found */ + } + + DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n", + (int)exp.help.exp_rtsp_info.pbtype, + exp.help.exp_rtsp_info.loport, + exp.help.exp_rtsp_info.hiport); + + LOCK_BH(&ip_rtsp_lock); + exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */ + exp.help.exp_rtsp_info.len = hdrslen; + + exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; + exp.mask.src.ip = 0xffffffff; + exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip; + exp.mask.dst.ip = 0xffffffff; + exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport; + exp.mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff; + exp.tuple.dst.protonum = IPPROTO_UDP; + exp.mask.dst.protonum = 0xffff; + + DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", + NIPQUAD(exp.tuple.src.ip), + ntohs(exp.tuple.src.u.tcp.port), + NIPQUAD(exp.tuple.dst.ip), + ntohs(exp.tuple.dst.u.tcp.port)); + + /* pass the request off to the nat helper */ + rc = ip_conntrack_expect_related(ct, &exp); + UNLOCK_BH(&ip_rtsp_lock); + if (rc == 0) + { + DEBUGP("ip_conntrack_expect_related succeeded\n"); + } + else + { + INFOP("ip_conntrack_expect_related failed (%d)\n", rc); + } + } + + return NF_ACCEPT; +} + +/* inbound packet: server->client */ +static int +help_in(const struct iphdr* iph, size_t pktlen, + struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) +{ + return NF_ACCEPT; +} + +static int +help(const struct iphdr* iph, size_t pktlen, + struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ + struct tcphdr* tcph = (void*)iph + iph->ihl * 4; + u_int32_t tcplen = pktlen - iph->ihl * 4; + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) + { + DEBUGP("conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) + { + DEBUGP("tcplen = %u\n", (unsigned)tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char*)tcph, tcplen, 0))) + { + DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + switch (CTINFO2DIR(ctinfo)) + { + case IP_CT_DIR_ORIGINAL: + help_out(iph, pktlen, ct, ctinfo); + break; + case IP_CT_DIR_REPLY: + help_in(iph, pktlen, ct, ctinfo); + break; + default: + /* oops */ + } + + return NF_ACCEPT; +} + +static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS]; +static char rtsp_names[MAX_PORTS][10]; + +/* This function is intentionally _NOT_ defined as __exit */ +static void +fini(void) +{ + int i; + for (i = 0; i < num_ports; i++) + { + DEBUGP("unregistering port %d\n", ports[i]); + ip_conntrack_helper_unregister(&rtsp_helpers[i]); + } +} + +static int __init +init(void) +{ + int i, ret; + struct ip_conntrack_helper *hlpr; + char *tmpname; + + printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n"); + + if (max_outstanding < 1) + { + printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n"); + return -EBUSY; + } + if (setup_timeout < 0) + { + printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n"); + return -EBUSY; + } + + /* If no port given, default to standard rtsp port */ + if (ports[0] == 0) + { + ports[0] = RTSP_PORT; + } + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) + { + hlpr = &rtsp_helpers[i]; + memset(hlpr, 0, sizeof(struct ip_conntrack_helper)); + hlpr->tuple.src.u.tcp.port = htons(ports[i]); + hlpr->tuple.dst.protonum = IPPROTO_TCP; + hlpr->mask.src.u.tcp.port = 0xFFFF; + hlpr->mask.dst.protonum = 0xFFFF; + hlpr->max_expected = max_outstanding; + hlpr->timeout = setup_timeout; + hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT; + hlpr->me = ip_conntrack_rtsp; + hlpr->help = help; + + tmpname = &rtsp_names[i][0]; + if (ports[i] == RTSP_PORT) + { + sprintf(tmpname, "rtsp"); + } + else + { + sprintf(tmpname, "rtsp-%d", i); + } + hlpr->name = tmpname; + + DEBUGP("port #%d: %d\n", i, ports[i]); + + ret = ip_conntrack_helper_register(hlpr); + + if (ret) + { + printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]); + fini(); + return -EBUSY; + } + num_ports++; + } + return 0; +} + +#ifdef CONFIG_IP_NF_NAT_NEEDED +EXPORT_SYMBOL(ip_rtsp_lock); +#endif + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2003-12-10 20:50:26.980332712 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_standalone.c 2003-12-10 23:14:22.974462048 +0100 @@ -105,6 +105,9 @@ len += sprintf(buffer + len, "[ASSURED] "); len += sprintf(buffer + len, "use=%u ", atomic_read(&conntrack->ct_general.use)); +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + len += sprintf(buffer + len, "mark=%ld ", conntrack->mark); +#endif len += sprintf(buffer + len, "\n"); return len; @@ -186,6 +189,26 @@ return ip_conntrack_confirm(*pskb); } +static unsigned int ip_conntrack_defrag(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + /* Previously seen (loopback)? Ignore. Do this before + fragment check. */ + if ((*pskb)->nfct) + return NF_ACCEPT; + + /* Gather fragments. */ + if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { + *pskb = ip_ct_gather_frags(*pskb); + if (!*pskb) + return NF_STOLEN; + } + return NF_ACCEPT; +} + static unsigned int ip_refrag(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, @@ -226,6 +249,15 @@ return ip_conntrack_in(hooknum, pskb, in, out, okfn); } +/* At the very first: defragment */ +static struct nf_hook_ops ip_conntrack_defrag_ops = { + .hook = ip_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, +}; + /* Connection tracking may drop packets, but never alters them, so make it the first hook. */ static struct nf_hook_ops ip_conntrack_in_ops = { @@ -236,6 +268,14 @@ .priority = NF_IP_PRI_CONNTRACK, }; +static struct nf_hook_ops ip_conntrack_defrag_local_out_ops = { + .hook = ip_conntrack_defrag, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_CONNTRACK_DEFRAG, +}; + static struct nf_hook_ops ip_conntrack_local_out_ops = { .hook = ip_conntrack_local, .owner = THIS_MODULE, @@ -368,10 +408,20 @@ if (!proc) goto cleanup_init; proc->owner = THIS_MODULE; + ret = nf_register_hook(&ip_conntrack_defrag_ops); + if (ret < 0) { + printk("ip_conntrack: can't register pre-routing defrag hook.\n"); + goto cleanup_proc; + } + ret = nf_register_hook(&ip_conntrack_defrag_local_out_ops); + if (ret < 0) { + printk("ip_conntrack: can't register local_out defrag hook.\n"); + goto cleanup_defragops; + } ret = nf_register_hook(&ip_conntrack_in_ops); if (ret < 0) { printk("ip_conntrack: can't register pre-routing hook.\n"); - goto cleanup_proc; + goto cleanup_defraglocalops; } ret = nf_register_hook(&ip_conntrack_local_out_ops); if (ret < 0) { @@ -409,6 +459,10 @@ nf_unregister_hook(&ip_conntrack_local_out_ops); cleanup_inops: nf_unregister_hook(&ip_conntrack_in_ops); + cleanup_defraglocalops: + nf_unregister_hook(&ip_conntrack_defrag_local_out_ops); + cleanup_defragops: + nf_unregister_hook(&ip_conntrack_defrag_ops); cleanup_proc: proc_net_remove("ip_conntrack"); cleanup_init: @@ -417,13 +471,20 @@ return ret; } -/* FIXME: Allow NULL functions and sub in pointers to generic for - them. --RR */ +/** + * ip_conntrack_protocol_register - Register layer 4 protocol helper + * @proto: structure describing this layer 4 protocol helper + * + * This function is called by layer 4 protocol helpers to register + * themselves with the conntrack core. + */ int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto) { int ret = 0; struct list_head *i; + /* FIXME: Allow NULL functions and sub in pointers to generic for + them. --RR */ WRITE_LOCK(&ip_conntrack_lock); list_for_each(i, &protocol_list) { if (((struct ip_conntrack_protocol *)i)->proto @@ -440,12 +501,20 @@ return ret; } +/** + * ip_conntrack_protocol_unregister - Unregister layer 4 protocol helper + * @proto: structure describing this layer 4 protocol helper + * + * This function is called byh layer 4 protocol helpers to unregister + * themselvers from the conntrack core. Please note that all conntrack + * entries for this protocol are deleted from the conntrack hash table. + */ void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto) { WRITE_LOCK(&ip_conntrack_lock); - /* ip_ct_find_proto() returns proto_generic in case there is no protocol - * helper. So this should be enough - HW */ + /* ip_ct_find_proto() returns proto_generic in case there is no + * protocol helper. So this should be enough - HW */ LIST_DELETE(&protocol_list, proto); WRITE_UNLOCK(&ip_conntrack_lock); @@ -486,6 +555,7 @@ EXPORT_SYMBOL(ip_conntrack_helper_unregister); EXPORT_SYMBOL(ip_ct_selective_cleanup); EXPORT_SYMBOL(ip_ct_refresh); +EXPORT_SYMBOL(ip_ct_death_by_timeout); EXPORT_SYMBOL(ip_ct_find_proto); EXPORT_SYMBOL(__ip_ct_find_proto); EXPORT_SYMBOL(ip_ct_find_helper); @@ -500,5 +570,6 @@ EXPORT_SYMBOL(ip_conntrack_expect_list); EXPORT_SYMBOL(ip_conntrack_lock); EXPORT_SYMBOL(ip_conntrack_hash); +EXPORT_SYMBOL(ip_conntrack_untracked); EXPORT_SYMBOL_GPL(ip_conntrack_find_get); EXPORT_SYMBOL_GPL(ip_conntrack_put); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_talk.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_talk.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_talk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_talk.c 2003-12-10 23:14:15.480601288 +0100 @@ -0,0 +1,360 @@ +/* + * talk extension for IP connection tracking. + * Jozsef Kadlecsik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_nat_talk.o talk=[0|1] ntalk=[0|1] ntalk2=[01] + * + * talk=[0|1] disable|enable old talk support + * ntalk=[0|1] disable|enable ntalk support + * ntalk2=[0|1] disable|enable ntalk2 support + * + * The default is talk=1 ntalk=1 ntalk2=1 + * + * The helper does not support simultaneous talk requests. + ** + * + * ASCII art on talk protocols + * + * + * caller server callee server + * | \ / + * | \ / + * | \ / + * | / + * | / \ + * 2 | 1 / \ 3 + * caller client ----------- callee client + * 4 + * + * 1. caller client <-> callee server: LOOK_UP, then ANNOUNCE invitation + * ( 2. caller client <-> caller server: LEAVE_INVITE to server ) + * 3. callee client <-> caller server: LOOK_UP invitation + * 4. callee client <-> caller client: talk data channel + * + * [1]: M. Hunter, talk: a historical protocol for interactive communication + * draft-hunter-talk-00.txt + * [2]: D.B. Chapman, E.D. Zwicky: Building Internet Firewalls (O'Reilly) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Default all talk protocols are supported */ +static int talk = 1; +static int ntalk = 1; +static int ntalk2 = 1; +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("talk connection tracking module"); +MODULE_LICENSE("GPL"); +#ifdef MODULE_PARM +MODULE_PARM(talk, "i"); +MODULE_PARM_DESC(talk, "support (old) talk protocol"); +MODULE_PARM(ntalk, "i"); +MODULE_PARM_DESC(ntalk, "support ntalk protocol"); +MODULE_PARM(ntalk2, "i"); +MODULE_PARM_DESC(ntalk2, "support ntalk2 protocol"); +#endif + +DECLARE_LOCK(ip_talk_lock); +struct module *ip_conntrack_talk = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static int talk_expect(struct ip_conntrack *ct); +static int ntalk_expect(struct ip_conntrack *ct); + +static int (*talk_expectfn[2])(struct ip_conntrack *ct) = {talk_expect, ntalk_expect}; + +static int talk_help_response(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + int talk_port, + u_char mode, + u_char type, + u_char answer, + struct talk_addr *addr) +{ + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_expect expect, *exp = &expect; + struct ip_ct_talk_expect *exp_talk_info = &exp->help.exp_talk_info; + + DEBUGP("ip_ct_talk_help_response: %u.%u.%u.%u:%u, type %d answer %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + type, answer); + + if (!(answer == SUCCESS && type == mode)) + return NF_ACCEPT; + + memset(&expect, 0, sizeof(expect)); + + if (type == ANNOUNCE) { + + DEBUGP("ip_ct_talk_help_response: ANNOUNCE\n"); + + /* update the talk info */ + LOCK_BH(&ip_talk_lock); + exp_talk_info->port = htons(talk_port); + + /* expect callee client -> caller server message */ + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[dir].tuple.src.ip, + { 0 } }, + { ct->tuplehash[dir].tuple.dst.ip, + { .tcp = { htons(talk_port) } }, + IPPROTO_UDP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }}); + + exp->expectfn = talk_expectfn[talk_port - TALK_PORT]; + + DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller daemon %u.%u.%u.%u:%u!\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.udp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.udp.port)); + + /* Ignore failure; should only happen with NAT */ + ip_conntrack_expect_related(ct, &expect); + UNLOCK_BH(&ip_talk_lock); + } + if (type == LOOK_UP) { + + DEBUGP("ip_ct_talk_help_response: LOOK_UP\n"); + + /* update the talk info */ + LOCK_BH(&ip_talk_lock); + exp_talk_info->port = addr->ta_port; + + /* expect callee client -> caller client connection */ + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, + { 0 } }, + { addr->ta_addr, + { addr->ta_port }, + IPPROTO_TCP }}); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + + exp->expectfn = NULL; + + DEBUGP("ip_ct_talk_help_response: callee client %u.%u.%u.%u:%u -> caller client %u.%u.%u.%u:%u!\n", + NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), + NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); + + /* Ignore failure; should only happen with NAT */ + ip_conntrack_expect_related(ct, &expect); + UNLOCK_BH(&ip_talk_lock); + } + + return NF_ACCEPT; +} + +/* FIXME: This should be in userspace. Later. */ +static int talk_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + int talk_port, + u_char mode) +{ + struct udphdr *udph = (void *)iph + iph->ihl * 4; + const char *data = (const char *)udph + sizeof(struct udphdr); + int dir = CTINFO2DIR(ctinfo); + size_t udplen; + + DEBUGP("ip_ct_talk_help: help entered\n"); + + /* Until there's been traffic both ways, don't look in packets. */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { + DEBUGP("ip_ct_talk_help: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole UDP header? */ + udplen = len - iph->ihl * 4; + if (udplen < sizeof(struct udphdr)) { + DEBUGP("ip_ct_talk_help: too short for udph, udplen = %u\n", (unsigned)udplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + /* FIXME: Source route IP option packets --RR */ + if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, + csum_partial((char *)udph, udplen, 0))) { + DEBUGP("ip_ct_talk_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + udph, udplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + DEBUGP("ip_ct_talk_help: %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(udph->source), NIPQUAD(iph->daddr), ntohs(udph->dest)); + + if (dir == IP_CT_DIR_ORIGINAL) + return NF_ACCEPT; + + if (talk_port == TALK_PORT + && udplen == sizeof(struct udphdr) + sizeof(struct talk_response)) + return talk_help_response(iph, len, ct, ctinfo, talk_port, mode, + ((struct talk_response *)data)->type, + ((struct talk_response *)data)->answer, + &(((struct talk_response *)data)->addr)); + else if (talk_port == NTALK_PORT + && ntalk + && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_response) + && ((struct ntalk_response *)data)->vers == NTALK_VERSION) + return talk_help_response(iph, len, ct, ctinfo, talk_port, mode, + ((struct ntalk_response *)data)->type, + ((struct ntalk_response *)data)->answer, + &(((struct ntalk_response *)data)->addr)); + else if (talk_port == NTALK_PORT + && ntalk2 + && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_response) + && ((struct ntalk2_response *)data)->vers == NTALK2_VERSION) + return talk_help_response(iph, len, ct, ctinfo, talk_port, mode, + ((struct ntalk2_response *)data)->type, + ((struct ntalk2_response *)data)->answer, + &(((struct ntalk2_response *)data)->addr)); + else { + DEBUGP("ip_ct_talk_help: not ntalk/ntalk2 response, datalen %u != %u or %u + max 256\n", + (unsigned)udplen - sizeof(struct udphdr), + sizeof(struct ntalk_response), sizeof(struct ntalk2_response)); + return NF_ACCEPT; + } +} + +static int lookup_help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(iph, len, ct, ctinfo, TALK_PORT, LOOK_UP); +} + +static int lookup_nhelp(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(iph, len, ct, ctinfo, NTALK_PORT, LOOK_UP); +} + +static struct ip_conntrack_helper lookup_helpers[2] = + { { { NULL, NULL }, + "talk", /* name */ + 0, /* flags */ + NULL, /* module */ + 1, /* max_expected */ + 240, /* timeout */ + { { 0, { __constant_htons(TALK_PORT) } }, /* tuple */ + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + lookup_help }, /* helper */ + { { NULL, NULL }, + "ntalk", /* name */ + 0, /* flags */ + NULL, /* module */ + 1, /* max_expected */ + 240, /* timeout */ + { { 0, { __constant_htons(NTALK_PORT) } }, /* tuple */ + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + lookup_nhelp } /* helper */ + }; + +static int talk_expect(struct ip_conntrack *ct) +{ + DEBUGP("ip_conntrack_talk: calling talk_expectfn for ct %p\n", ct); + WRITE_LOCK(&ip_conntrack_lock); + ct->helper = &lookup_helpers[0]; + WRITE_UNLOCK(&ip_conntrack_lock); + + return NF_ACCEPT; /* unused */ +} + +static int ntalk_expect(struct ip_conntrack *ct) +{ + DEBUGP("ip_conntrack_talk: calling ntalk_expectfn for ct %p\n", ct); + WRITE_LOCK(&ip_conntrack_lock); + ct->helper = &lookup_helpers[1]; + WRITE_UNLOCK(&ip_conntrack_lock); + + return NF_ACCEPT; /* unused */ +} + +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(iph, len, ct, ctinfo, TALK_PORT, ANNOUNCE); +} + +static int nhelp(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) +{ + return talk_help(iph, len, ct, ctinfo, NTALK_PORT, ANNOUNCE); +} + +static struct ip_conntrack_helper talk_helpers[2] = + { { { NULL, NULL }, + "talk", /* name */ + 0, /* flags */ + THIS_MODULE, /* module */ + 1, /* max_expected */ + 240, /* timeout */ + { { 0, { __constant_htons(TALK_PORT) } }, /* tuple */ + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + help }, /* helper */ + { { NULL, NULL }, + "ntalk", /* name */ + 0, /* flags */ + THIS_MODULE, /* module */ + 1, /* max_expected */ + 240, /* timeout */ + { { 0, { __constant_htons(NTALK_PORT) } }, /* tuple */ + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { 0xFFFF } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + nhelp } /* helper */ + }; + +static int __init init(void) +{ + if (talk > 0) + ip_conntrack_helper_register(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_conntrack_helper_register(&talk_helpers[1]); + + return 0; +} + +static void __exit fini(void) +{ + if (talk > 0) + ip_conntrack_helper_unregister(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_conntrack_helper_unregister(&talk_helpers[1]); +} + +EXPORT_SYMBOL(ip_talk_lock); + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_tftp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_tftp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_conntrack_tftp.c 2003-11-26 21:43:31.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_conntrack_tftp.c 2003-12-10 23:13:21.271842272 +0100 @@ -97,8 +97,6 @@ for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { /* Create helper structure */ - memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); - tftp[i].tuple.dst.protonum = IPPROTO_UDP; tftp[i].tuple.src.u.udp.port = htons(ports[i]); tftp[i].mask.dst.protonum = 0xFFFF; diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_amanda.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_amanda.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_amanda.c 2003-11-26 21:43:24.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_amanda.c 2003-12-10 23:13:21.271842272 +0100 @@ -195,8 +195,6 @@ struct ip_nat_helper *hlpr; hlpr = &ip_nat_amanda_helper; - memset(hlpr, 0, sizeof(struct ip_nat_helper)); - hlpr->tuple.dst.protonum = IPPROTO_UDP; hlpr->tuple.src.u.udp.port = htons(10080); hlpr->mask.src.u.udp.port = 0xFFFF; diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_core.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_core.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_core.c 2003-11-26 21:43:07.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_core.c 2003-12-10 23:14:03.995347312 +0100 @@ -90,9 +90,16 @@ WRITE_UNLOCK(&ip_nat_lock); } -/* We do checksum mangling, so if they were wrong before they're still - * wrong. Also works for incomplete packets (eg. ICMP dest - * unreachables.) */ +/** + * ip_nat_cheat_check - Incremental checksum change for IP/TCP checksum + * @oldvalinv: bit-inverted old value of 32bit word + * @newval: new value of 32bit word + * @oldcheck: old checksum value + * + * This function implements incremental checksum mangling, so if a checksum + * was wrong it will still be wrong after mangling. Also works for incomplete + * packets (eg. ICMP dest unreachables). Return value is the new checksum. + */ u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) { @@ -118,7 +125,14 @@ return i; } -/* Is this tuple already taken? (not by us) */ +/** + * ip_nat_used_tuple - Is this tuple already in use? + * @tuple: tuple to be used for this check + * @ignored_conntrack: conntrack excluded from this check + * + * This function checks for the reply (inverted) tuple in the conntrack + * hash. This is necessarry with NAT, since there is no fixed mapping. + */ int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple, const struct ip_conntrack *ignored_conntrack) @@ -432,7 +446,7 @@ *tuple = *orig_tuple; while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum)) != NULL) { - DEBUGP("Found best for "); DUMP_TUPLE(tuple); + DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple); /* 3) The per-protocol part of the manip is made to map into the range to make a unique tuple. */ @@ -509,6 +523,19 @@ #endif }; +/** + * ip_nat_setup_info - Set up NAT mappings for NEW packet + * @conntrack: conntrack on which we operate + * @mr: address/port range which is valid for this NAT mapping + * @hooknum: hook at which this NAT mapping applies + * + * This function is called by NAT targets (SNAT,DNAT,...) and by + * the NAT application helper modules. It is called for the NEW packet + * of a connection in order to specify which NAT mappings shall apply to + * this connection at a given hook. + * + * Note: The reply mappings are created automagically by this function. + */ unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack, const struct ip_nat_multi_range *mr, @@ -573,9 +600,9 @@ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST", conntrack); DEBUGP("Original: "); - DUMP_TUPLE(&orig_tp); + DUMP_TUPLE_RAW(&orig_tp); DEBUGP("New: "); - DUMP_TUPLE(&new_tuple); + DUMP_TUPLE_RAW(&new_tuple); #endif /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT): @@ -810,7 +837,7 @@ /* Have to grab read lock before sibling_list traversal */ READ_LOCK(&ip_conntrack_lock); - list_for_each(cur_item, &ct->sibling_list) { + list_for_each_prev(cur_item, &ct->sibling_list) { exp = list_entry(cur_item, struct ip_conntrack_expect, expected_list); @@ -1010,7 +1037,11 @@ /* FIXME: Man, this is a hack. */ IP_NF_ASSERT(ip_conntrack_destroyed == NULL); ip_conntrack_destroyed = &ip_nat_cleanup_conntrack; - + + /* Initialize fake conntrack so that NAT will skip it */ + ip_conntrack_untracked.nat.info.initialized |= + (1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST); + return 0; } diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_cuseeme.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_cuseeme.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_cuseeme.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_cuseeme.c 2003-12-10 23:13:55.777596600 +0100 @@ -0,0 +1,289 @@ +/* CuSeeMe extension for UDP NAT alteration. + * (C) 2002 by Filip Sneppe + * based on ip_masq_cuseeme.c in 2.2 kernels + * + * ip_nat_cuseeme.c v0.0.7 2003-02-18 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_nat_cuseeme.o ports=port1,port2,...port + * + * Please give the ports of the CuSeeMe traffic you want to track. + * If you don't specify ports, the default will be UDP port 7648. + * + * CuSeeMe Protocol Documentation: + * http://cu-seeme.net/squeek/tech/contents.html + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Filip Sneppe "); +MODULE_DESCRIPTION("Netfilter NAT helper for CuSeeMe"); +MODULE_LICENSE("GPL"); + +#define MAX_PORTS 8 + +static int ports[MAX_PORTS]; +static int ports_c = 0; +#ifdef MODULE_PARM +MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of CuSeeMe reflectors"); +#endif + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* process packet from client->reflector, possibly manipulate client IP in payload */ +void cuseeme_mangle_outgoing(struct ip_conntrack *ct, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + struct sk_buff **pskb, + char *data, + unsigned int datalen) +{ + char new_port_ip[6]; + struct cu_header *cu_head=(struct cu_header *)data; + + DEBUGP("ip_nat_cuseeme: outgoing packet, ID %u, dest_family %u\n", + ntohs(cu_head->data_type), ntohs(cu_head->dest_family)); + + /* At least check that the data at offset 10 is the client's port and IP address */ + if ((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == cu_head->addr) && + (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port == cu_head->port)) { + DEBUGP("ip_nat_cuseeme: rewrite outgoing client %u.%u.%u.%u:%u->%u.%u.%u.%u:%u at offset 10\n", + NIPQUAD(cu_head->addr), + ntohs(cu_head->port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port)); + *((u_int16_t *)new_port_ip) = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; + *((u_int32_t *)(new_port_ip+2)) = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + /* at offset 10, replace 6 bytes containing port + IP address */ + ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + 10, 6, (char *)(new_port_ip), 6); + } else + DEBUGP("ip_nat_cuseeme: expected outgoing client %u.%u.%u.%u:%u, but got %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), + ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port), + NIPQUAD(cu_head->addr), + ntohs(cu_head->port)); +} + +/* process packet from reflector->client, possibly manipulate client IP & reflector IP in payload */ +void cuseeme_mangle_incoming(struct ip_conntrack *ct, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + struct sk_buff **pskb, + char *data, + unsigned int datalen) +{ + char new_port_ip[6]; + struct cu_header *cu_head = (struct cu_header *)data; + struct oc_header *oc_head = (struct oc_header *)data; + struct client_info *ci; + int i, off; + + + DEBUGP("ip_nat_cuseeme: incoming packet, ID %u, dest_family %u\n", + ntohs(cu_head->data_type), ntohs(cu_head->dest_family)); + + /* Check if we're really dealing with the client's port + IP address before rewriting */ + if((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip == cu_head->dest_addr) && + (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port == cu_head->dest_port)) { + DEBUGP("ip_nat_cuseeme: rewrite incoming client %u.%u.%u.%u:%u->%u.%u.%u.%u:%u at offset 2\n", + NIPQUAD(cu_head->dest_addr), + ntohs(cu_head->dest_port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), + ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port)); + *((u_int16_t *)new_port_ip) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; + *((u_int32_t *)(new_port_ip+2)) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + /* at offset 2, replace 6 bytes containing port + IP address */ + ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + 2, 6, (char *)(new_port_ip), 6); + } else + DEBUGP("ip_nat_cuseeme: expected incoming client %u.%u.%u.%u:%u, but got %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port), + NIPQUAD(cu_head->dest_addr), + ntohs(cu_head->dest_port)); + + /* Check if we're really dealing with the server's port + IP address before rewriting. + In some cases, the IP address == 0.0.0.0 so we don't rewrite anything */ + if((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip == cu_head->addr) && + (ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port == cu_head->port)) { + DEBUGP("in_nat_cuseeme: rewrite incoming server %u.%u.%u.%u:%u->%u.%u.%u.%u:%u at offset 10\n", + NIPQUAD(cu_head->addr), + ntohs(cu_head->port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip), + ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port)); + *((u_int16_t *)new_port_ip) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port; + *((u_int32_t *)(new_port_ip+2)) = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + /* at offset 10, replace 6 bytes containing port + IP address */ + ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + 10, 6, (char *)(new_port_ip), 6); + } else + /* Sometimes we find 0.0.0.0, sometimes an IP address - the docs say this field + is not that important so we're not logging this unless we're debugging */ + DEBUGP("ip_nat_cuseeme: no biggie, expected incoming server %u.%u.%u.%u:%u, but got %u.%u.%u.%u:%u\n", + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip), + ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.udp.port), + NIPQUAD(cu_head->addr), + ntohs(cu_head->port)); + + /* Spin through client_info structs until we find our own */ + if((ntohs(cu_head->data_type) == 101) && (datalen >= sizeof(struct oc_header))) { + DEBUGP("ip_nat_cuseeme: looping through %u client_info structs\n", oc_head->client_count); + for(i=0, off=sizeof(struct oc_header); + (i < oc_head->client_count && + off+sizeof(struct client_info) <= datalen); + i++) { + ci=(struct client_info *)(data+off); + DEBUGP("ip_nat_cuseeme: comparing %u.%u.%u.%u with %u.%u.%u.%u at offset %u\n", + NIPQUAD(ci->address), NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + (unsigned int)((void *)&(ci->address) - (void *)cu_head)); + if(ci->address == ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) { + /* mangle this IP address */ + DEBUGP("ip_nat_cuseeme: changing %u.%u.%u.%u->%u.%u.%u.%u at offset %u\n", + NIPQUAD(ci->address), + NIPQUAD(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip), + (unsigned int)((void *)&(ci->address) - (void *)cu_head)); + ip_nat_mangle_udp_packet(pskb, ct, ctinfo, + (unsigned int)((void *)&(ci->address) - (void *)cu_head), 4, + (char *)(&(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip)), 4); + break; + } else + off+=sizeof(struct client_info); + } + } else + DEBUGP("ip_nat_cuseeme: data_type %u, datalen %u < sizeof(struct oc_header) %u\n", + ntohs(cu_head->data_type), datalen, sizeof(struct oc_header)); +} + +static unsigned int +cuseeme_nat_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + int dir = CTINFO2DIR(ctinfo); + unsigned int datalen = (*pskb)->len - iph->ihl * 4 - sizeof(struct udphdr); + char *data = (char *) &udph[1]; + + DEBUGP("ip_nat_cuseeme: cuseeme_nat_help, direction: %s hook: %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???" + ); + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("ip_nat_cuseeme: not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????"); + return NF_ACCEPT; + } + + if(datalen < sizeof(struct cu_header)) { + /* packet too small */ + if (net_ratelimit()) + printk("ip_nat_cuseeme: payload too small (%u, should be >= %u)\n", + datalen, sizeof(struct cu_header)); + return NF_ACCEPT; + } + + + /* In the debugging output, "outgoing" is from client to server, and + "incoming" is from server to client */ + if(HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) + cuseeme_mangle_outgoing(ct, info, ctinfo, pskb, data, datalen); + else + cuseeme_mangle_incoming(ct, info, ctinfo, pskb, data, datalen); + + return NF_ACCEPT; +} + +static struct ip_nat_helper cuseeme[MAX_PORTS]; +static char cuseeme_names[MAX_PORTS][14]; /* cuseeme-65535 */ + +static void fini(void) +{ + int i; + + for (i = 0 ; i < ports_c; i++) { + DEBUGP("ip_nat_cuseeme: unregistering helper for port %d\n", ports[i]); + ip_nat_helper_unregister(&cuseeme[i]); + } +} + +static int __init init(void) +{ + int i, ret = 0; + char *tmpname; + + if (!ports[0]) + ports[0] = CUSEEME_PORT; + + for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { + memset(&cuseeme[i], 0, sizeof(struct ip_nat_helper)); + + cuseeme[i].tuple.dst.protonum = IPPROTO_UDP; + cuseeme[i].tuple.dst.u.udp.port = htons(ports[i]); + cuseeme[i].mask.dst.protonum = 0xFFFF; + cuseeme[i].mask.dst.u.udp.port = 0xFFFF; + cuseeme[i].help = cuseeme_nat_help; + cuseeme[i].flags = IP_NAT_HELPER_F_STANDALONE + + IP_NAT_HELPER_F_ALWAYS; /* dunno if IP_NAT_HELPER_F_ALWAYS + is stricly needed... */ + cuseeme[i].me = THIS_MODULE; + cuseeme[i].expect = NULL; /* cuseeme_nat_expected; */ + + tmpname = &cuseeme_names[i][0]; + if (ports[i] == CUSEEME_PORT) + sprintf(tmpname, "cuseeme"); + else + sprintf(tmpname, "cuseeme-%d", ports[i]); + cuseeme[i].name = tmpname; + + DEBUGP("ip_nat_cuseeme: registering helper for port %d: name %s\n", + ports[i], cuseeme[i].name); + ret = ip_nat_helper_register(&cuseeme[i]); + + if (ret) { + printk("ip_nat_cuseeme: unable to register helper for port %d\n", + ports[i]); + fini(); + return ret; + } + ports_c++; + } + return ret; +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_h323.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_h323.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_h323.c 2003-12-10 23:13:58.178231648 +0100 @@ -0,0 +1,419 @@ +/* + * H.323 'brute force' extension for NAT alteration. + * Jozsef Kadlecsik + * + * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. + * (http://www.coritel.it/projects/sofia/nat.html) + * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' + * the unregistered helpers to the conntrack entries. + */ + + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); +MODULE_LICENSE("GPL"); + +DECLARE_LOCK_EXTERN(ip_h323_lock); +struct module *ip_nat_h323 = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: Time out? --RR */ + +static unsigned int +h225_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info); + +static unsigned int h225_nat_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb); + +static struct ip_nat_helper h245 = + { { NULL, NULL }, + "H.245", /* name */ + 0, /* flags */ + NULL, /* module */ + { { 0, { 0 } }, /* tuple */ + { 0, { 0 }, IPPROTO_TCP } }, + { { 0, { 0xFFFF } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + h225_nat_help, /* helper */ + h225_nat_expected /* expectfn */ + }; + +static unsigned int +h225_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info) +{ + struct ip_nat_multi_range mr; + u_int32_t newdstip, newsrcip, newip; + u_int16_t port; + struct ip_ct_h225_expect *exp_info; + struct ip_ct_h225_master *master_info; + struct ip_conntrack *master = master_ct(ct); + unsigned int is_h225, ret; + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + + IP_NF_ASSERT(!(info->initialized & (1<master->expectant->help.ct_h225_info; + exp_info = &ct->master->help.exp_h225_info; + + LOCK_BH(&ip_h323_lock); + + DEBUGP("master: "); + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); + DEBUGP("conntrack: "); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + if (exp_info->dir == IP_CT_DIR_ORIGINAL) { + /* Make connection go to the client. */ + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + } else { + /* Make the connection go to the server */ + newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + } + port = exp_info->port; + is_h225 = master_info->is_h225 == H225_PORT; + UNLOCK_BH(&ip_h323_lock); + + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) + newip = newsrcip; + else + newip = newdstip; + + DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); + + mr.rangesize = 1; + /* We don't want to manip the per-protocol, just the IPs... */ + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + /* ... unless we're doing a MANIP_DST, in which case, make + sure we map to the correct port */ + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { + mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + mr.range[0].min = mr.range[0].max + = ((union ip_conntrack_manip_proto) + { .tcp = { port } }); + } + + ret = ip_nat_setup_info(ct, &mr, hooknum); + + if (is_h225) { + DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); + /* NAT expectfn called with ip_nat_lock write-locked */ + info->helper = &h245; + } + return ret; +} + +static int h323_signal_address_fixup(struct ip_conntrack *ct, + struct sk_buff **pskb, + enum ip_conntrack_info ctinfo) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *)iph + iph->ihl*4; + char *data = (char *) tcph + tcph->doff * 4; + u_int32_t tcplen = (*pskb)->len - iph->ihl*4; + u_int32_t datalen = tcplen - tcph->doff*4; + struct ip_ct_h225_master *info = &ct->help.ct_h225_info; + u_int32_t newip; + u_int16_t port; + int i; + + MUST_BE_LOCKED(&ip_h323_lock); + + DEBUGP("h323_signal_address_fixup: %s %s\n", + between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) + ? "yes" : "no", + between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) + ? "yes" : "no"); + if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) + || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) + return 1; + + DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", + info->offset[IP_CT_DIR_ORIGINAL], + info->offset[IP_CT_DIR_REPLY], + tcplen); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + for (i = 0; i < IP_CT_DIR_MAX; i++) { + DEBUGP("h323_signal_address_fixup: %s %s\n", + info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", + i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); + if (!between(info->seq[i], ntohl(tcph->seq), + ntohl(tcph->seq) + datalen)) + continue; + if (!between(info->seq[i] + 6, ntohl(tcph->seq), + ntohl(tcph->seq) + datalen)) { + /* Partial retransmisison. It's a cracker being funky. */ + if (net_ratelimit()) { + printk("H.323_NAT: partial packet %u/6 in %u/%u\n", + info->seq[i], + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + } + return 0; + } + + /* Change address inside packet to match way we're mapping + this connection. */ + if (i == IP_CT_DIR_ORIGINAL) { + newip = ct->tuplehash[!info->dir].tuple.dst.ip; + port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; + } else { + newip = ct->tuplehash[!info->dir].tuple.src.ip; + port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; + } + + DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", + NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), + ntohs(*((u_int16_t *)(data + info->offset[i] + 4)))); + + /* Modify the packet */ + *(u_int32_t *)(data + info->offset[i]) = newip; + *(u_int16_t *)(data + info->offset[i] + 4) = port; + + DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", + i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", + NIPQUAD(*((u_int32_t *)(data + info->offset[i]))), + ntohs(*((u_int16_t *)(data + info->offset[i] + 4)))); + } + + /* fix checksum information */ + + (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4, + datalen, 0); + + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcph->doff*4, + (*pskb)->csum)); + ip_send_check(iph); + + return 1; +} + +static int h323_data_fixup(struct ip_ct_h225_expect *info, + struct ip_conntrack *ct, + struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *expect) +{ + u_int32_t newip; + u_int16_t port; + struct ip_conntrack_tuple newtuple; + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *)iph + iph->ihl*4; + char *data = (char *) tcph + tcph->doff * 4; + u_int32_t tcplen = (*pskb)->len - iph->ihl*4; + struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; + int is_h225; + + MUST_BE_LOCKED(&ip_h323_lock); + DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + if (!between(expect->seq + 6, ntohl(tcph->seq), + ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { + /* Partial retransmisison. It's a cracker being funky. */ + if (net_ratelimit()) { + printk("H.323_NAT: partial packet %u/6 in %u/%u\n", + expect->seq, + ntohl(tcph->seq), + ntohl(tcph->seq) + tcplen - tcph->doff * 4); + } + return 0; + } + + /* Change address inside packet to match way we're mapping + this connection. */ + if (info->dir == IP_CT_DIR_REPLY) { + /* Must be where client thinks server is */ + newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + /* Expect something from client->server */ + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + } else { + /* Must be where server thinks client is */ + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + /* Expect something from server->client */ + newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + } + + is_h225 = (master_info->is_h225 == H225_PORT); + + if (is_h225) { + newtuple.dst.protonum = IPPROTO_TCP; + newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; + } else { + newtuple.dst.protonum = IPPROTO_UDP; + newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; + } + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(info->port); port != 0; port++) { + if (is_h225) + newtuple.dst.u.tcp.port = htons(port); + else + newtuple.dst.u.udp.port = htons(port); + + if (ip_conntrack_change_expect(expect, &newtuple) == 0) + break; + } + if (port == 0) { + DEBUGP("h323_data_fixup: no free port found!\n"); + return 0; + } + + port = htons(port); + + DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", + NIPQUAD(*((u_int32_t *)(data + info->offset))), + ntohs(*((u_int16_t *)(data + info->offset + 4)))); + + /* Modify the packet */ + *(u_int32_t *)(data + info->offset) = newip; + *(u_int16_t *)(data + info->offset + 4) = port; + + DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", + NIPQUAD(*((u_int32_t *)(data + info->offset))), + ntohs(*((u_int16_t *)(data + info->offset + 4)))); + + /* fix checksum information */ + /* FIXME: usually repeated multiple times in the case of H.245! */ + + (*pskb)->csum = csum_partial((char *)tcph + tcph->doff*4, + tcplen - tcph->doff*4, 0); + + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcph->doff*4, + (*pskb)->csum)); + ip_send_check(iph); + + return 1; +} + +static unsigned int h225_nat_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + int dir; + struct ip_ct_h225_expect *exp_info; + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + dir = CTINFO2DIR(ctinfo); + DEBUGP("nat_h323: dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("nat_h323: Not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + return NF_ACCEPT; + } + + if (!exp) { + LOCK_BH(&ip_h323_lock); + if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { + UNLOCK_BH(&ip_h323_lock); + return NF_DROP; + } + UNLOCK_BH(&ip_h323_lock); + return NF_ACCEPT; + } + + exp_info = &exp->help.exp_h225_info; + + LOCK_BH(&ip_h323_lock); + if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { + UNLOCK_BH(&ip_h323_lock); + return NF_DROP; + } + UNLOCK_BH(&ip_h323_lock); + + return NF_ACCEPT; +} + +static struct ip_nat_helper h225 = + { { NULL, NULL }, + "H.225", /* name */ + IP_NAT_HELPER_F_ALWAYS, /* flags */ + THIS_MODULE, /* module */ + { { 0, { .tcp = { __constant_htons(H225_PORT) } } }, /* tuple */ + { 0, { 0 }, IPPROTO_TCP } }, + { { 0, { .tcp = { 0xFFFF } } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + h225_nat_help, /* helper */ + h225_nat_expected /* expectfn */ + }; + +static int __init init(void) +{ + int ret; + + ret = ip_nat_helper_register(&h225); + + if (ret != 0) + printk("ip_nat_h323: cannot initialize the module!\n"); + + return ret; +} + +static void __exit fini(void) +{ + ip_nat_helper_unregister(&h225); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_helper.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_helper.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_helper.c 2003-11-26 21:43:08.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_helper.c 2003-12-10 23:14:03.996347160 +0100 @@ -147,9 +147,19 @@ return 1; } -/* Generic function for mangling variable-length address changes inside - * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX - * command in FTP). +/** + * ip_nat_mangle_tcp_packet - Mangle and potentially resize payload packet + * @skb: pointer to skb of packet on which we operate + * @ct: conntrack of the connection to which this packet belongs + * @ctinfo: conntrack_info of the connection to which this packet belongs + * @match_offset: offset in bytes where to-be-manipulated part starts + * @match_len: lenght of the to-be-manipulated part + * @rep_buffer: pointer to buffer containing replacement + * @rep_len: length of replacement + * + * Generic function for mangling fixed and variable-length changes inside + * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX command + * in FTP). * * Takes care about all the nasty sequence number changes, checksumming, * skb enlargement, ... @@ -195,16 +205,27 @@ return 1; } -/* Generic function for mangling variable-length address changes inside - * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX - * command in the Amanda protocol) +/** + * ip_nat_mangle_udp_packet - Mangle and potentially resize payload packet + * @skb: pointer to skb of packet on which we operate + * @ct: conntrack of the connection to which this packet belongs + * @ctinfo: conntrack_info of the connection to which this packet belongs + * @match_offset: offset in bytes where to-be-manipulated part starts + * @match_len: lenght of the to-be-manipulated part + * @rep_buffer: pointer to buffer containing replacement + * @rep_len: length of replacement + * + * Generic function for mangling fixed and variable-length changes inside + * NATed TCP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX + * commad in the Amanda protocol) * * Takes care about all the nasty sequence number changes, checksumming, * skb enlargement, ... * - * XXX - This function could be merged with ip_nat_mangle_tcp_packet which - * should be fairly easy to do. - */ + * FIXME: should be unified with ip_nat_mangle_tcp_packet!! + * + * */ + int ip_nat_mangle_udp_packet(struct sk_buff **pskb, struct ip_conntrack *ct, @@ -402,6 +423,13 @@ return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask); } +/** + * ip_nat_helper_register - Register NAT application helper + * @me: structure describing the helper + * + * This function is called by NAT application helpers to register + * themselves with the NAT core. + */ int ip_nat_helper_register(struct ip_nat_helper *me) { int ret = 0; @@ -428,6 +456,13 @@ return ret; } +/** + * ip_nat_helper_unregister - Unregister NAT application helper + * @me: structure describing the helper + * + * This function is called by NAT application helpers to unregister + * themselves from the NAT core. + */ void ip_nat_helper_unregister(struct ip_nat_helper *me) { WRITE_LOCK(&ip_nat_lock); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_mms.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_mms.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_mms.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_mms.c 2003-12-10 23:14:02.757535488 +0100 @@ -0,0 +1,350 @@ +/* MMS extension for TCP NAT alteration. + * (C) 2002 by Filip Sneppe + * based on ip_nat_ftp.c and ip_nat_irc.c + * + * ip_nat_mms.c v0.3 2002-09-22 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_nat_mms.o ports=port1,port2,...port + * + * Please give the ports of all MMS servers You wish to connect to. + * If you don't specify ports, the default will be TCP port 1755. + * + * More info on MMS protocol, firewalls and NAT: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp + * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp + * + * The SDP project people are reverse-engineering MMS: + * http://get.to/sdp + */ + +/* FIXME: issue with UDP & fragmentation with this URL: + http://www.cnn.com/video/world/2002/01/21/jb.shoe.bomb.cafe.cnn.low.asx + may be related to out-of-order first packets: + basically the expectation is set up correctly, then the server sends + a first UDP packet which is fragmented plus arrives out-of-order. + the MASQUERADING firewall with ip_nat_mms loaded responds with + an ICMP unreachable back to the server */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#define DUMP_BYTES(address, counter) \ +({ \ + int temp_counter; \ + for(temp_counter=0; temp_counter"); +MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module"); +MODULE_LICENSE("GPL"); + +DECLARE_LOCK_EXTERN(ip_mms_lock); + +/* FIXME: Time out? --RR */ + +static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info, + struct ip_conntrack *ct, + struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *expect) +{ + u_int32_t newip; + struct ip_conntrack_tuple t; + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + char *data = (char *)tcph + tcph->doff * 4; + int i, j, k, port; + u_int16_t mms_proto; + + u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET); + u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET); + u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET); + + int zero_padding; + + char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */ + char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */ + char proto_string[6]; + + MUST_BE_LOCKED(&ip_mms_lock); + + /* what was the protocol again ? */ + mms_proto = expect->tuple.dst.protonum; + sprintf(proto_string, "%u", mms_proto); + + DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n", + expect->seq, ct_mms_info->len, ntohl(tcph->seq), + mms_proto == IPPROTO_UDP ? "UDP" + : mms_proto == IPPROTO_TCP ? "TCP":proto_string); + + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + + /* Alter conntrack's expectations. */ + t = expect->tuple; + t.dst.ip = newip; + for (port = ct_mms_info->port; port != 0; port++) { + t.dst.u.tcp.port = htons(port); + if (ip_conntrack_change_expect(expect, &t) == 0) { + DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port); + break; + } + } + + if(port == 0) + return 0; + + sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u", + NIPQUAD(newip), + expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP" + : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string, + port); + DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer); + + memset(unicode_buffer, 0, sizeof(char)*75); + + for (i=0; ipadding, ct_mms_info->len); + DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len); + DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60); + + /* add end of packet to it */ + for (j=0; jpadding; ++j) { + DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", + i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j)); + *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j); + } + + /* pad with zeroes at the end ? see explanation of weird math below */ + zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8; + for (k=0; k chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", + *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); + + /* explanation, before I forget what I did: + strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8; + divide by 8 and add 3 to compute the mms_chunkLenLM field, + but note that things may have to be padded with zeroes to align by 8 + bytes, hence we add 7 and divide by 8 to get the correct length */ + *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8); + *mms_chunkLenLV = *mms_chunkLenLM+2; + *mms_messageLength = *mms_chunkLenLV*8; + + DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", + *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); + + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + expect->seq - ntohl(tcph->seq), + ct_mms_info->len + ct_mms_info->padding, unicode_buffer, + strlen(buffer)*2 + ct_mms_info->padding + zero_padding); + DUMP_BYTES(unicode_buffer, 60); + + return 1; +} + +static unsigned int +mms_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info) +{ + struct ip_nat_multi_range mr; + u_int32_t newdstip, newsrcip, newip; + + struct ip_conntrack *master = master_ct(ct); + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); + + DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n"); + + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) + newip = newsrcip; + else + newip = newdstip; + + DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); + + mr.rangesize = 1; + /* We don't want to manip the per-protocol, just the IPs. */ + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + return ip_nat_setup_info(ct, &mr, hooknum); +} + + +static unsigned int mms_nat_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + unsigned int datalen; + int dir; + struct ip_ct_mms_expect *ct_mms_info; + + if (!exp) + DEBUGP("ip_nat_mms: no exp!!"); + + ct_mms_info = &exp->help.exp_mms_info; + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + dir = CTINFO2DIR(ctinfo); + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + ||(hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("ip_nat_mms: mms_nat_help: not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + return NF_ACCEPT; + } + DEBUGP("ip_nat_mms: mms_nat_help: beyond not touching (dir %s at hook %s)\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + + datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; + + DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len, + exp->seq + ct_mms_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + + LOCK_BH(&ip_mms_lock); + /* Check wether the whole IP/proto/port pattern is carried in the payload */ + if (between(exp->seq + ct_mms_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen)) { + if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) { + UNLOCK_BH(&ip_mms_lock); + return NF_DROP; + } + } else { + /* Half a match? This means a partial retransmisison. + It's a cracker being funky. */ + if (net_ratelimit()) { + printk("ip_nat_mms: partial packet %u/%u in %u/%u\n", + exp->seq, ct_mms_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + } + UNLOCK_BH(&ip_mms_lock); + return NF_DROP; + } + UNLOCK_BH(&ip_mms_lock); + + return NF_ACCEPT; +} + +static struct ip_nat_helper mms[MAX_PORTS]; +static char mms_names[MAX_PORTS][10]; + +/* Not __exit: called from init() */ +static void fini(void) +{ + int i; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]); + ip_nat_helper_unregister(&mms[i]); + } +} + +static int __init init(void) +{ + int i, ret = 0; + char *tmpname; + + if (ports[0] == 0) + ports[0] = MMS_PORT; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + + memset(&mms[i], 0, sizeof(struct ip_nat_helper)); + + mms[i].tuple.dst.protonum = IPPROTO_TCP; + mms[i].tuple.src.u.tcp.port = htons(ports[i]); + mms[i].mask.dst.protonum = 0xFFFF; + mms[i].mask.src.u.tcp.port = 0xFFFF; + mms[i].help = mms_nat_help; + mms[i].me = THIS_MODULE; + mms[i].flags = 0; + mms[i].expect = mms_nat_expected; + + tmpname = &mms_names[i][0]; + if (ports[i] == MMS_PORT) + sprintf(tmpname, "mms"); + else + sprintf(tmpname, "mms-%d", i); + mms[i].name = tmpname; + + DEBUGP("ip_nat_mms: register helper for port %d\n", + ports[i]); + ret = ip_nat_helper_register(&mms[i]); + + if (ret) { + printk("ip_nat_mms: error registering " + "helper for port %d\n", ports[i]); + fini(); + return ret; + } + ports_c++; + } + + return ret; +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_pptp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_pptp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_pptp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_pptp.c 2003-11-17 09:09:34.000000000 +0100 @@ -0,0 +1,475 @@ +/* + * ip_nat_pptp.c - Version 1.5 + * + * NAT support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2003 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * TODO: - Support for multiple calls within one session + * (needs netfilter newnat code) + * - NAT to a unique tuple, not to TCP source port + * (needs netfilter tuple reservation) + * + * Changes: + * 2002-02-10 - Version 1.3 + * - Use ip_nat_mangle_tcp_packet() because of cloned skb's + * in local connections (Philip Craig ) + * - add checks for magicCookie and pptp version + * - make argument list of pptp_{out,in}bound_packet() shorter + * - move to C99 style initializers + * - print version number at module loadtime + * 2003-09-22 - Version 1.5 + * - use SNATed tcp sourceport as callid, since we get called before + * TCP header is mangled (Philip Craig ) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IP_NAT_PPTP_VERSION "1.5" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); + + +#if 0 +#include "ip_conntrack_pptp_priv.h" +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ": " format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +static unsigned int +pptp_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info) +{ + struct ip_conntrack *master = master_ct(ct); + struct ip_nat_multi_range mr; + struct ip_ct_pptp_master *ct_pptp_info; + struct ip_nat_pptp *nat_pptp_info; + u_int32_t newip, newcid; + int ret; + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); + + DEBUGP("we have a connection!\n"); + + LOCK_BH(&ip_pptp_lock); + ct_pptp_info = &master->help.ct_pptp_info; + nat_pptp_info = &master->nat.help.nat_pptp_info; + + /* need to alter GRE tuple because conntrack expectfn() used 'wrong' + * (unmanipulated) values */ + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { + DEBUGP("completing tuples with NAT info \n"); + /* we can do this, since we're unconfirmed */ + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == + htonl(ct_pptp_info->pac_call_id)) { + /* assume PNS->PAC */ + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = + htonl(nat_pptp_info->pns_call_id); + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = + htonl(nat_pptp_info->pns_call_id); + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + newcid = htonl(nat_pptp_info->pac_call_id); + } else { + /* assume PAC->PNS */ + ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = + htonl(nat_pptp_info->pac_call_id); + ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = + htonl(nat_pptp_info->pac_call_id); + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newcid = htonl(nat_pptp_info->pns_call_id); + } + } else { + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == + htonl(ct_pptp_info->pac_call_id)) { + /* assume PNS->PAC */ + newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + newcid = htonl(ct_pptp_info->pns_call_id); + } + else { + /* assume PAC->PNS */ + newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + newcid = htonl(ct_pptp_info->pac_call_id); + } + } + + mr.rangesize = 1; + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + mr.range[0].min = mr.range[0].max = + ((union ip_conntrack_manip_proto ) { newcid }); + DEBUGP("change ip to %u.%u.%u.%u\n", + NIPQUAD(newip)); + DEBUGP("change key to 0x%x\n", ntohl(newcid)); + ret = ip_nat_setup_info(ct, &mr, hooknum); + + UNLOCK_BH(&ip_pptp_lock); + + return ret; + +} + +/* outbound packets == from PNS to PAC */ +static inline unsigned int +pptp_outbound_pkt(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *exp) + +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl*4; + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) + ((void *)tcph + tcph->doff*4); + + struct PptpControlHeader *ctlh; + union pptp_ctrl_union pptpReq; + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; + + u_int16_t msg, *cid = NULL, new_callid; + + /* FIXME: size checks !!! */ + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); + + new_callid = htons(ct_pptp_info->pns_call_id); + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REQUEST: + cid = &pptpReq.ocreq->callID; + /* FIXME: ideally we would want to reserve a call ID + * here. current netfilter NAT core is not able to do + * this :( For now we use TCP source port. This breaks + * multiple calls within one control session */ + + /* save original call ID in nat_info */ + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; + + /* don't use tcph->source since we are at a DSTmanip + * hook (e.g. PREROUTING) and pkt is not mangled yet */ + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; + + /* save new call ID in ct info */ + ct_pptp_info->pns_call_id = ntohs(new_callid); + break; + case PPTP_IN_CALL_REPLY: + cid = &pptpReq.icreq->callID; + break; + case PPTP_CALL_CLEAR_REQUEST: + cid = &pptpReq.clrreq->callID; + break; + default: + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); + /* fall through */ + + case PPTP_SET_LINK_INFO: + /* only need to NAT in case PAC is behind NAT box */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + IP_NF_ASSERT(cid); + + DEBUGP("altering call id from 0x%04x to 0x%04x\n", + ntohs(*cid), ntohs(new_callid)); + + /* mangle packet */ + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph, + sizeof(new_callid), (char *)&new_callid, + sizeof(new_callid)); + + return NF_ACCEPT; +} + +/* inbound packets == from PAC to PNS */ +static inline unsigned int +pptp_inbound_pkt(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *oldexp) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl*4; + struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) + ((void *)tcph + tcph->doff*4); + + struct PptpControlHeader *ctlh; + union pptp_ctrl_union pptpReq; + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; + + u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; + u_int32_t old_dst_ip; + + struct ip_conntrack_tuple t, inv_t; + struct ip_conntrack_tuple *orig_t, *reply_t; + + /* FIXME: size checks !!! */ + ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); + pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); + + new_pcid = htons(nat_pptp_info->pns_call_id); + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REPLY: + pcid = &pptpReq.ocack->peersCallID; + cid = &pptpReq.ocack->callID; + if (!oldexp) { + DEBUGP("outcall but no expectation\n"); + break; + } + old_dst_ip = oldexp->tuple.dst.ip; + t = oldexp->tuple; + invert_tuplepr(&inv_t, &t); + + /* save original PAC call ID in nat_info */ + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; + + /* alter expectation */ + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) { + /* expectation for PNS->PAC direction */ + t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); + t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); + inv_t.src.ip = reply_t->src.ip; + inv_t.dst.ip = reply_t->dst.ip; + inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); + } else { + /* expectation for PAC->PNS direction */ + t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); + t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); + inv_t.src.ip = orig_t->src.ip; + inv_t.dst.ip = orig_t->dst.ip; + inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); + inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); + } + + if (!ip_conntrack_change_expect(oldexp, &t)) { + DEBUGP("successfully changed expect\n"); + } else { + DEBUGP("can't change expect\n"); + } + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t); + ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t); + break; + case PPTP_IN_CALL_CONNECT: + pcid = &pptpReq.iccon->peersCallID; + if (!oldexp) + break; + old_dst_ip = oldexp->tuple.dst.ip; + t = oldexp->tuple; + + /* alter expectation, no need for callID */ + if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) { + /* expectation for PNS->PAC direction */ + t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + } else { + /* expectation for PAC->PNS direction */ + t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + } + + if (!ip_conntrack_change_expect(oldexp, &t)) { + DEBUGP("successfully changed expect\n"); + } else { + DEBUGP("can't change expect\n"); + } + break; + case PPTP_IN_CALL_REQUEST: + /* only need to nat in case PAC is behind NAT box */ + break; + case PPTP_WAN_ERROR_NOTIFY: + pcid = &pptpReq.wanerr->peersCallID; + break; + case PPTP_CALL_DISCONNECT_NOTIFY: + pcid = &pptpReq.disc->callID; + break; + + default: + DEBUGP("unknown inbound packet %s\n", + (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); + /* fall through */ + + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* mangle packet */ + IP_NF_ASSERT(pcid); + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", + ntohs(*pcid), ntohs(new_pcid)); + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph, + sizeof(new_pcid), (char *)&new_pcid, + sizeof(new_pcid)); + + if (new_cid) { + IP_NF_ASSERT(cid); + DEBUGP("altering call id from 0x%04x to 0x%04x\n", + ntohs(*cid), ntohs(new_cid)); + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)cid - (void *)pptph, + sizeof(new_cid), (char *)&new_cid, + sizeof(new_cid)); + } + + /* great, at least we don't need to resize packets */ + return NF_ACCEPT; +} + + +static unsigned int tcp_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl*4; + unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4; + struct pptp_pkt_hdr *pptph; + + int dir; + + DEBUGP("entering\n"); + + /* Only mangle things once: DST for original direction + and SRC for reply direction. */ + dir = CTINFO2DIR(ctinfo); + if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC + && dir == IP_CT_DIR_ORIGINAL) + || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST + && dir == IP_CT_DIR_REPLY))) { + DEBUGP("Not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" + : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???"); + return NF_ACCEPT; + } + + /* if packet is too small, just skip it */ + if (datalen < sizeof(struct pptp_pkt_hdr)+ + sizeof(struct PptpControlHeader)) { + DEBUGP("pptp packet too short\n"); + return NF_ACCEPT; + } + + pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4); + + /* if it's not a control message, we can't handle it */ + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { + DEBUGP("not a pptp control packet\n"); + return NF_ACCEPT; + } + + LOCK_BH(&ip_pptp_lock); + + if (dir == IP_CT_DIR_ORIGINAL) { + /* reuqests sent by client to server (PNS->PAC) */ + pptp_outbound_pkt(pskb, ct, ctinfo, exp); + } else { + /* response from the server to the client (PAC->PNS) */ + pptp_inbound_pkt(pskb, ct, ctinfo, exp); + } + + UNLOCK_BH(&ip_pptp_lock); + + return NF_ACCEPT; +} + +/* nat helper struct for control connection */ +static struct ip_nat_helper pptp_tcp_helper = { + .list = { NULL, NULL }, + .name = "pptp", + .flags = IP_NAT_HELPER_F_ALWAYS, + .me = THIS_MODULE, + .tuple = { .src = { .ip = 0, + .u = { .tcp = { .port = + __constant_htons(PPTP_CONTROL_PORT) } + } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = IPPROTO_TCP + } + }, + + .mask = { .src = { .ip = 0, + .u = { .tcp = { .port = 0xFFFF } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = 0xFFFF + } + }, + .help = tcp_help, + .expect = pptp_nat_expected +}; + + +static int __init init(void) +{ + DEBUGP("%s: registering NAT helper\n", __FILE__); + if (ip_nat_helper_register(&pptp_tcp_helper)) { + printk(KERN_ERR "Unable to register NAT application helper " + "for pptp\n"); + return -EIO; + } + + printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); + return 0; +} + +static void __exit fini(void) +{ + DEBUGP("cleanup_module\n" ); + ip_nat_helper_unregister(&pptp_tcp_helper); + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_proto_gre.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_proto_gre.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_proto_gre.c 2003-11-17 09:09:34.000000000 +0100 @@ -0,0 +1,225 @@ +/* + * ip_nat_proto_gre.c - Version 1.2 + * + * NAT protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2003 by Harald Welte + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ + ": " format, ## args) +#else +#define DEBUGP(x, args...) +#endif + +/* is key in given range between min and max */ +static int +gre_in_range(const struct ip_conntrack_tuple *tuple, + enum ip_nat_manip_type maniptype, + const union ip_conntrack_manip_proto *min, + const union ip_conntrack_manip_proto *max) +{ + u_int32_t key; + + if (maniptype == IP_NAT_MANIP_SRC) + key = tuple->src.u.gre.key; + else + key = tuple->dst.u.gre.key; + + return ntohl(key) >= ntohl(min->gre.key) + && ntohl(key) <= ntohl(max->gre.key); +} + +/* generate unique tuple ... */ +static int +gre_unique_tuple(struct ip_conntrack_tuple *tuple, + const struct ip_nat_range *range, + enum ip_nat_manip_type maniptype, + const struct ip_conntrack *conntrack) +{ + u_int32_t min, i, range_size; + u_int32_t key = 0, *keyptr; + + if (maniptype == IP_NAT_MANIP_SRC) + keyptr = &tuple->src.u.gre.key; + else + keyptr = &tuple->dst.u.gre.key; + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + + switch (tuple->dst.u.gre.version) { + case 0: + DEBUGP("NATing GRE version 0 (ct=%p)\n", + conntrack); + min = 1; + range_size = 0xffffffff; + break; + case GRE_VERSION_PPTP: + DEBUGP("%p: NATing GRE PPTP\n", + conntrack); + min = 1; + range_size = 0xffff; + break; + default: + printk(KERN_WARNING "nat_gre: unknown GRE version\n"); + return 0; + break; + } + + } else { + min = ntohl(range->min.gre.key); + range_size = ntohl(range->max.gre.key) - min + 1; + } + + DEBUGP("min = %u, range_size = %u\n", min, range_size); + + for (i = 0; i < range_size; i++, key++) { + *keyptr = htonl(min + key % range_size); + if (!ip_nat_used_tuple(tuple, conntrack)) + return 1; + } + + DEBUGP("%p: no NAT mapping\n", conntrack); + + return 0; +} + +/* manipulate a GRE packet according to maniptype */ +static void +gre_manip_pkt(struct iphdr *iph, size_t len, + const struct ip_conntrack_manip *manip, + enum ip_nat_manip_type maniptype) +{ + struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl); + struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh; + + /* we only have destination manip of a packet, since 'source key' + * is not present in the packet itself */ + if (maniptype == IP_NAT_MANIP_DST) { + /* key manipulation is always dest */ + switch (greh->version) { + case 0: + if (!greh->key) { + DEBUGP("can't nat GRE w/o key\n"); + break; + } + if (greh->csum) { + /* FIXME: Never tested this code... */ + *(gre_csum(greh)) = + ip_nat_cheat_check(~*(gre_key(greh)), + manip->u.gre.key, + *(gre_csum(greh))); + } + *(gre_key(greh)) = manip->u.gre.key; + break; + case GRE_VERSION_PPTP: + DEBUGP("call_id -> 0x%04x\n", + ntohl(manip->u.gre.key)); + pgreh->call_id = htons(ntohl(manip->u.gre.key)); + break; + default: + DEBUGP("can't nat unknown GRE version\n"); + break; + } + } +} + +/* print out a nat tuple */ +static unsigned int +gre_print(char *buffer, + const struct ip_conntrack_tuple *match, + const struct ip_conntrack_tuple *mask) +{ + unsigned int len = 0; + + if (mask->dst.u.gre.version) + len += sprintf(buffer + len, "version=%d ", + ntohs(match->dst.u.gre.version)); + + if (mask->dst.u.gre.protocol) + len += sprintf(buffer + len, "protocol=0x%x ", + ntohs(match->dst.u.gre.protocol)); + + if (mask->src.u.gre.key) + len += sprintf(buffer + len, "srckey=0x%x ", + ntohl(match->src.u.gre.key)); + + if (mask->dst.u.gre.key) + len += sprintf(buffer + len, "dstkey=0x%x ", + ntohl(match->src.u.gre.key)); + + return len; +} + +/* print a range of keys */ +static unsigned int +gre_print_range(char *buffer, const struct ip_nat_range *range) +{ + if (range->min.gre.key != 0 + || range->max.gre.key != 0xFFFF) { + if (range->min.gre.key == range->max.gre.key) + return sprintf(buffer, "key 0x%x ", + ntohl(range->min.gre.key)); + else + return sprintf(buffer, "keys 0x%u-0x%u ", + ntohl(range->min.gre.key), + ntohl(range->max.gre.key)); + } else + return 0; +} + +/* nat helper struct */ +static struct ip_nat_protocol gre = + { { NULL, NULL }, "GRE", IPPROTO_GRE, + gre_manip_pkt, + gre_in_range, + gre_unique_tuple, + gre_print, + gre_print_range + }; + +static int __init init(void) +{ + if (ip_nat_protocol_register(&gre)) + return -EIO; + + return 0; +} + +static void __exit fini(void) +{ + ip_nat_protocol_unregister(&gre); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_quake3.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_quake3.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_quake3.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_quake3.c 2003-12-10 23:14:06.244005464 +0100 @@ -0,0 +1,249 @@ +/* Quake3 extension for UDP NAT alteration. + * (C) 2002 by Filip Sneppe + * based on ip_nat_ftp.c and ip_nat_tftp.c + * + * ip_nat_quake3.c v0.0.3 2002-08-31 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_nat_quake3.o ports=port1,port2,...port + * + * please give the ports of all Quake3 master servers You wish to + * connect to. If you don't specify ports, the default will be UDP + * port 27950. + * + * Thanks to the Ethereal folks for their analysis of the Quake3 protocol. + * + * Notes: + * - If you're one of those people who would try anything to lower + * latency while playing Quake (and who isn't :-) ), you may want to + * consider not loading ip_nat_quake3 at all and just MASQUERADE all + * outgoing UDP traffic. + * This will make ip_conntrack_quake3 add the necessary expectations, + * but there will be no overhead for client->server UDP streams. If + * ip_nat_quake3 is loaded, quake3_nat_expected will be called per NAT + * hook for every packet in the client->server UDP stream. + * - Only SNAT/MASQUEARDE targets are useful for ip_nat_quake3. + * The IP addresses in the master connection payload (=IP addresses + * of Quake servers) have no relation with the master server so + * DNAT'ing the master connection to a server should not change the + * expected connections. + * - Not tested due to lack of equipment: + * - multiple Quake3 clients behind one MASQUERADE gateway + * - what if Quake3 client is running on router too + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Filip Sneppe "); +MODULE_DESCRIPTION("Netfilter NAT helper for Quake III Arena"); +MODULE_LICENSE("GPL"); + +#define MAX_PORTS 8 + +static int ports[MAX_PORTS]; +static int ports_c = 0; +#ifdef MODULE_PARM +MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of Quake III master servers"); +#endif + +/* Quake3 master server reply will add > 100 expectations per reply packet; when + doing lots of printk's, klogd may not be able to read /proc/kmsg fast enough */ +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static struct quake3_search quake3s_nat = { "****", "getserversResponse", sizeof("getserversResponse") - 1 }; + +static unsigned int +quake3_nat_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + struct ip_conntrack_tuple repl; + int dir = CTINFO2DIR(ctinfo); + int i; + + DEBUGP("ip_nat_quake3: quake3_nat_help, direction: %s hook: %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???" + ); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("ip_nat_quake3: Not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????"); + return NF_ACCEPT; + } + + if (!exp) { + DEBUGP("no conntrack expectation to modify\n"); + return NF_ACCEPT; + } + + if (strnicmp((const char *)udph + 12, quake3s_nat.pattern, quake3s_nat.plen) == 0) { + for(i=31; /* 8 bytes UDP hdr, 4 bytes filler, 18 bytes "getserversResponse", 1 byte "\" */ + i+6 < ntohs(udph->len); + i+=7) { + DEBUGP("ip_nat_quake3: adding server at offset %u/%u %u.%u.%u.%u:%u\n", + i, ntohs(udph->len), + NIPQUAD( (u_int32_t) *( (u_int32_t *)( (int)udph + i ) ) ), + ntohs((__u16) *( (__u16 *)( (int)udph + i + 4 ) ) ) ); + + memset(&repl, 0, sizeof(repl)); + + repl.dst.protonum = IPPROTO_UDP; + repl.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + repl.dst.ip = *( (u_int32_t *)( (int)udph + i ) ); + repl.dst.u.udp.port = (__u16) *( (__u16 *)( (int)udph + i + 4 ) ); + + ip_conntrack_change_expect(exp, &repl); + } + } + return NF_ACCEPT; +} + +static unsigned int +quake3_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info) +{ + const struct ip_conntrack *master = ct->master->expectant; + struct ip_nat_multi_range mr; + u_int32_t newsrcip, newdstip, newip; +#if 0 + const struct ip_conntrack_tuple *repl = + &master->tuplehash[IP_CT_DIR_REPLY].tuple; + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl*4; +#endif + + DEBUGP("ip_nat_quake3: quake3_nat_expected: here we are\n"); + DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); + + newdstip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) { + newip = newsrcip; + DEBUGP("hook: %s orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " + "newsrc: %u.%u.%u.%u\n", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????", + NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), + NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), + NIPQUAD(newip)); + + } else { + newip = newdstip; + DEBUGP("hook: %s orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " + "newdst: %u.%u.%u.%u\n", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "????", + NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), + NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), + NIPQUAD(newip)); + } + + mr.rangesize = 1; + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + return ip_nat_setup_info(ct,&mr,hooknum); +} + +static struct ip_nat_helper quake3[MAX_PORTS]; +static char quake3_names[MAX_PORTS][13]; /* quake3-65535 */ + +static void fini(void) +{ + int i; + + for (i = 0 ; i < ports_c; i++) { + DEBUGP("ip_nat_quake3: unregistering helper for port %d\n", ports[i]); + ip_nat_helper_unregister(&quake3[i]); + } +} + +static int __init init(void) + { + int i, ret = 0; + char *tmpname; + + if (!ports[0]) + ports[0] = QUAKE3_MASTER_PORT; + + for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { + memset(&quake3[i], 0, sizeof(struct ip_nat_helper)); + + quake3[i].tuple.dst.protonum = IPPROTO_UDP; + quake3[i].tuple.src.u.udp.port = htons(ports[i]); + quake3[i].mask.dst.protonum = 0xFFFF; + quake3[i].mask.src.u.udp.port = 0xFFFF; + quake3[i].help = quake3_nat_help; + quake3[i].flags = 0; + quake3[i].me = THIS_MODULE; + quake3[i].expect = quake3_nat_expected; + + tmpname = &quake3_names[i][0]; + if (ports[i] == QUAKE3_MASTER_PORT) + sprintf(tmpname, "quake3"); + else + sprintf(tmpname, "quake3-%d", i); + quake3[i].name = tmpname; + + DEBUGP("ip_nat_quake3: registering helper for port %d: name %s\n", + ports[i], quake3[i].name); + ret = ip_nat_helper_register(&quake3[i]); + + if (ret) { + printk("ip_nat_quake3: unable to register helper for port %d\n", + ports[i]); + fini(); + return ret; + } + ports_c++; + } + return ret; + } + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_rtsp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_rtsp.c 2003-12-10 23:14:12.892994664 +0100 @@ -0,0 +1,625 @@ +/* + * RTSP extension for TCP NAT alteration + * (C) 2003 by Tom Marshall + * based on ip_nat_irc.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_nat_rtsp.o ports=port1,port2,...port + * stunaddr=
+ * destaction=[auto|strip|none] + * + * If no ports are specified, the default will be port 554 only. + * + * stunaddr specifies the address used to detect that a client is using STUN. + * If this address is seen in the destination parameter, it is assumed that + * the client has already punched a UDP hole in the firewall, so we don't + * mangle the client_port. If none is specified, it is autodetected. It + * only needs to be set if you have multiple levels of NAT. It should be + * set to the external address that the STUN clients detect. Note that in + * this case, it will not be possible for clients to use UDP with servers + * between the NATs. + * + * If no destaction is specified, auto is used. + * destaction=auto: strip destination parameter if it is not stunaddr. + * destaction=strip: always strip destination parameter (not recommended). + * destaction=none: do not touch destination parameter (not recommended). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#define NF_NEED_STRNCASECMP +#define NF_NEED_STRTOU16 +#include +#define NF_NEED_MIME_NEXTLINE +#include + +#define INFOP(args...) printk(KERN_INFO __FILE__ ":" __FUNCTION__ ":" args) +#ifdef IP_NF_RTSP_DEBUG +#define DEBUGP(args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ ":" args); +#else +#define DEBUGP(args...) +#endif + +#define MAX_PORTS 8 +#define DSTACT_AUTO 0 +#define DSTACT_STRIP 1 +#define DSTACT_NONE 2 + +static int ports[MAX_PORTS]; +static char* stunaddr = NULL; +static char* destaction = NULL; + +static int num_ports = 0; +static u_int32_t extip = 0; +static int dstact = 0; + +MODULE_AUTHOR("Tom Marshall "); +MODULE_DESCRIPTION("RTSP network address translation module"); +MODULE_LICENSE("GPL"); +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); +MODULE_PARM(stunaddr, "s"); +MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); +MODULE_PARM(destaction, "s"); +MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); +#endif + +/* protects rtsp part of conntracks */ +DECLARE_LOCK_EXTERN(ip_rtsp_lock); + +#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } + +/*** helper functions ***/ + +static void +get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) +{ + struct iphdr* iph = (struct iphdr*)skb->nh.iph; + struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4); + + *pptcpdata = (char*)tcph + tcph->doff*4; + *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata; +} + +/*** nat functions ***/ + +/* + * Mangle the "Transport:" header: + * - Replace all occurences of "client_port=" + * - Handle destination parameter + * + * In: + * ct, ctinfo = conntrack context + * pskb = packet + * tranoff = Transport header offset from TCP data + * tranlen = Transport header length (incl. CRLF) + * rport_lo = replacement low port (host endian) + * rport_hi = replacement high port (host endian) + * + * Returns packet size difference. + * + * Assumes that a complete transport header is present, ending with CR or LF + */ +static int +rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect* exp, + struct sk_buff** pskb, uint tranoff, uint tranlen) +{ + char* ptcp; + uint tcplen; + char* ptran; + char rbuf1[16]; /* Replacement buffer (one port) */ + uint rbuf1len; /* Replacement len (one port) */ + char rbufa[16]; /* Replacement buffer (all ports) */ + uint rbufalen; /* Replacement len (all ports) */ + u_int32_t newip; + u_int16_t loport, hiport; + uint off = 0; + uint diff; /* Number of bytes we removed */ + + struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; + struct ip_conntrack_tuple t; + + char szextaddr[15+1]; + uint extaddrlen; + int is_stun; + + get_skb_tcpdata(*pskb, &ptcp, &tcplen); + ptran = ptcp+tranoff; + + if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || + tranlen < 10 || !iseol(ptran[tranlen-1]) || + nf_strncasecmp(ptran, "Transport:", 10) != 0) + { + INFOP("sanity check failed\n"); + return 0; + } + off += 10; + SKIP_WSPACE(ptcp+tranoff, tranlen, off); + + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + t = exp->tuple; + t.dst.ip = newip; + + extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip)) + : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip)); + DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); + + rbuf1len = rbufalen = 0; + switch (prtspexp->pbtype) + { + case pb_single: + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ + { + t.dst.u.udp.port = htons(loport); + if (ip_conntrack_change_expect(exp, &t) == 0) + { + DEBUGP("using port %hu\n", loport); + break; + } + } + if (loport != 0) + { + rbuf1len = sprintf(rbuf1, "%hu", loport); + rbufalen = sprintf(rbufa, "%hu", loport); + } + break; + case pb_range: + for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ + { + t.dst.u.udp.port = htons(loport); + if (ip_conntrack_change_expect(exp, &t) == 0) + { + hiport = loport + ~exp->mask.dst.u.udp.port; + DEBUGP("using ports %hu-%hu\n", loport, hiport); + break; + } + } + if (loport != 0) + { + rbuf1len = sprintf(rbuf1, "%hu", loport); + rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); + } + break; + case pb_discon: + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ + { + t.dst.u.udp.port = htons(loport); + if (ip_conntrack_change_expect(exp, &t) == 0) + { + DEBUGP("using port %hu (1 of 2)\n", loport); + break; + } + } + for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ + { + t.dst.u.udp.port = htons(hiport); + if (ip_conntrack_change_expect(exp, &t) == 0) + { + DEBUGP("using port %hu (2 of 2)\n", hiport); + break; + } + } + if (loport != 0 && hiport != 0) + { + rbuf1len = sprintf(rbuf1, "%hu", loport); + if (hiport == loport+1) + { + rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); + } + else + { + rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); + } + } + break; + default: + /* oops */ + } + + if (rbuf1len == 0) + { + return 0; /* cannot get replacement port(s) */ + } + + /* Transport: tran;field;field=val,tran;field;field=val,... */ + while (off < tranlen) + { + uint saveoff; + const char* pparamend; + uint nextparamoff; + + pparamend = memchr(ptran+off, ',', tranlen-off); + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; + nextparamoff = pparamend-ptcp; + + /* + * We pass over each param twice. On the first pass, we look for a + * destination= field. It is handled by the security policy. If it + * is present, allowed, and equal to our external address, we assume + * that STUN is being used and we leave the client_port= field alone. + */ + is_stun = 0; + saveoff = off; + while (off < nextparamoff) + { + const char* pfieldend; + uint nextfieldoff; + + pfieldend = memchr(ptran+off, ';', nextparamoff-off); + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; + + if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) + { + if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) + { + is_stun = 1; + } + if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) + { + diff = nextfieldoff-off; + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + off, diff, NULL, 0)) + { + /* mangle failed, all we can do is bail */ + return 0; + } + get_skb_tcpdata(*pskb, &ptcp, &tcplen); + ptran = ptcp+tranoff; + tranlen -= diff; + nextparamoff -= diff; + nextfieldoff -= diff; + } + } + + off = nextfieldoff; + } + if (is_stun) + { + continue; + } + off = saveoff; + while (off < nextparamoff) + { + const char* pfieldend; + uint nextfieldoff; + + pfieldend = memchr(ptran+off, ';', nextparamoff-off); + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; + + if (strncmp(ptran+off, "client_port=", 12) == 0) + { + u_int16_t port; + uint numlen; + uint origoff; + uint origlen; + char* rbuf = rbuf1; + uint rbuflen = rbuf1len; + + off += 12; + origoff = (ptran-ptcp)+off; + origlen = 0; + numlen = nf_strtou16(ptran+off, &port); + off += numlen; + origlen += numlen; + if (port != prtspexp->loport) + { + DEBUGP("multiple ports found, port %hu ignored\n", port); + } + else + { + if (ptran[off] == '-' || ptran[off] == '/') + { + off++; + origlen++; + numlen = nf_strtou16(ptran+off, &port); + off += numlen; + origlen += numlen; + rbuf = rbufa; + rbuflen = rbufalen; + } + + /* + * note we cannot just memcpy() if the sizes are the same. + * the mangle function does skb resizing, checks for a + * cloned skb, and updates the checksums. + * + * parameter 4 below is offset from start of tcp data. + */ + diff = origlen-rbuflen; + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + origoff, origlen, rbuf, rbuflen)) + { + /* mangle failed, all we can do is bail */ + return 0; + } + get_skb_tcpdata(*pskb, &ptcp, &tcplen); + ptran = ptcp+tranoff; + tranlen -= diff; + nextparamoff -= diff; + nextfieldoff -= diff; + } + } + + off = nextfieldoff; + } + + off = nextparamoff; + } + + return 1; +} + +static unsigned int +expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info) +{ + struct ip_nat_multi_range mr; + u_int32_t newdstip, newsrcip, newip; + + struct ip_conntrack *master = master_ct(ct); + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); + + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip; + + DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip)); + + mr.rangesize = 1; + /* We don't want to manip the per-protocol, just the IPs. */ + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + return ip_nat_setup_info(ct, &mr, hooknum); +} + +static uint +help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect* exp, struct sk_buff** pskb) +{ + char* ptcp; + uint tcplen; + uint hdrsoff; + uint hdrslen; + uint lineoff; + uint linelen; + uint off; + + struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; + struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); + + struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; + + get_skb_tcpdata(*pskb, &ptcp, &tcplen); + + hdrsoff = exp->seq - ntohl(tcph->seq); + hdrslen = prtspexp->len; + off = hdrsoff; + + while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) + { + if (linelen == 0) + { + break; + } + if (off > hdrsoff+hdrslen) + { + INFOP("!! overrun !!"); + break; + } + DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); + + if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) + { + uint oldtcplen = tcplen; + if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen)) + { + break; + } + get_skb_tcpdata(*pskb, &ptcp, &tcplen); + hdrslen -= (oldtcplen-tcplen); + off -= (oldtcplen-tcplen); + lineoff -= (oldtcplen-tcplen); + linelen -= (oldtcplen-tcplen); + DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); + } + } + + return NF_ACCEPT; +} + +static uint +help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect* exp, struct sk_buff** pskb) +{ + /* XXX: unmangle */ + return NF_ACCEPT; +} + +static uint +help(struct ip_conntrack* ct, + struct ip_conntrack_expect* exp, + struct ip_nat_info* info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff** pskb) +{ + struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; + struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4); + uint datalen; + int dir; + struct ip_ct_rtsp_expect* ct_rtsp_info; + int rc = NF_ACCEPT; + + if (ct == NULL || exp == NULL || info == NULL || pskb == NULL) + { + DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb); + return NF_ACCEPT; + } + + ct_rtsp_info = &exp->help.exp_rtsp_info; + + /* + * Only mangle things once: original direction in POST_ROUTING + * and reply direction on PRE_ROUTING. + */ + dir = CTINFO2DIR(ctinfo); + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) + { + DEBUGP("Not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + return NF_ACCEPT; + } + DEBUGP("got beyond not touching\n"); + + datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; + + LOCK_BH(&ip_rtsp_lock); + /* Ensure the packet contains all of the marked data */ + if (!between(exp->seq + ct_rtsp_info->len, + ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) + { + /* Partial retransmission? Probably a hacker. */ + if (net_ratelimit()) + { + INFOP("partial packet %u/%u in %u/%u\n", + exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); + } + UNLOCK_BH(&ip_rtsp_lock); + return NF_DROP; + } + + switch (dir) + { + case IP_CT_DIR_ORIGINAL: + rc = help_out(ct, ctinfo, exp, pskb); + break; + case IP_CT_DIR_REPLY: + rc = help_in(ct, ctinfo, exp, pskb); + break; + default: + /* oops */ + } + UNLOCK_BH(&ip_rtsp_lock); + + return rc; +} + +static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS]; +static char rtsp_names[MAX_PORTS][10]; + +/* This function is intentionally _NOT_ defined as __exit */ +static void +fini(void) +{ + int i; + + for (i = 0; i < num_ports; i++) + { + DEBUGP("unregistering helper for port %d\n", ports[i]); + ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]); + } +} + +static int __init +init(void) +{ + int ret = 0; + int i; + struct ip_nat_helper* hlpr; + char* tmpname; + + printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n"); + + if (ports[0] == 0) + { + ports[0] = RTSP_PORT; + } + + for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) + { + hlpr = &ip_nat_rtsp_helpers[i]; + memset(hlpr, 0, sizeof(struct ip_nat_helper)); + + hlpr->tuple.dst.protonum = IPPROTO_TCP; + hlpr->tuple.src.u.tcp.port = htons(ports[i]); + hlpr->mask.src.u.tcp.port = 0xFFFF; + hlpr->mask.dst.protonum = 0xFFFF; + hlpr->help = help; + hlpr->flags = 0; + hlpr->me = THIS_MODULE; + hlpr->expect = expected; + + tmpname = &rtsp_names[i][0]; + if (ports[i] == RTSP_PORT) + { + sprintf(tmpname, "rtsp"); + } + else + { + sprintf(tmpname, "rtsp-%d", i); + } + hlpr->name = tmpname; + + DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name); + ret = ip_nat_helper_register(hlpr); + + if (ret) + { + printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]); + fini(); + return 1; + } + num_ports++; + } + if (stunaddr != NULL) + { + extip = in_aton(stunaddr); + } + if (destaction != NULL) + { + if (strcmp(destaction, "auto") == 0) + { + dstact = DSTACT_AUTO; + } + if (strcmp(destaction, "strip") == 0) + { + dstact = DSTACT_STRIP; + } + if (strcmp(destaction, "none") == 0) + { + dstact = DSTACT_NONE; + } + } + return ret; +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_rule.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_rule.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_rule.c 2003-11-26 21:43:38.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_rule.c 2003-12-10 23:13:24.662326840 +0100 @@ -67,7 +67,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* POST_ROUTING */ @@ -75,7 +75,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_OUT */ @@ -83,7 +83,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } } }, @@ -92,7 +92,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_error), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, { } }, "ERROR" diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_standalone.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_standalone.c 2003-11-26 21:45:10.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_standalone.c 2003-12-10 23:14:03.996347160 +0100 @@ -260,7 +260,13 @@ }; #endif -/* Protocol registration. */ +/** + * ip_nat_protocol_register - Register a layer 4 protocol helper + * @proto: structure describing this helper + * + * This function is called by NAT layer 4 protocol helpers to register + * themselvers with the NAT core. + */ int ip_nat_protocol_register(struct ip_nat_protocol *proto) { int ret = 0; @@ -281,9 +287,16 @@ return ret; } -/* Noone stores the protocol anywhere; simply delete it. */ +/** + * ip_nat_protocol_unregister - Unregister a layer 4 protocol helper + * @proto: sturcture describing the helper + * + * This function is called by NAT layer 4 protocol helpers to + * unregister themselves from the NAT core. + */ void ip_nat_protocol_unregister(struct ip_nat_protocol *proto) { + /* Noone stores the protocol anywhere; simply delete it. */ WRITE_LOCK(&ip_nat_lock); LIST_DELETE(&protos, proto); WRITE_UNLOCK(&ip_nat_lock); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_talk.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_talk.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_talk.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_talk.c 2003-12-10 23:14:15.481601136 +0100 @@ -0,0 +1,473 @@ +/* + * talk extension for UDP NAT alteration. + * Jozsef Kadlecsik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ip_nat_talk.o talk=[0|1] ntalk=[0|1] ntalk2=[0|1] + * + * talk=[0|1] disable|enable old talk support + * ntalk=[0|1] disable|enable ntalk support + * ntalk2=[0|1] disable|enable ntalk2 support + * + * The default is talk=1 ntalk=1 ntalk2=1 + * + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Default all talk protocols are supported */ +static int talk = 1; +static int ntalk = 1; +static int ntalk2 = 1; +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_DESCRIPTION("talk network address translation module"); +#ifdef MODULE_PARM +MODULE_PARM(talk, "i"); +MODULE_PARM_DESC(talk, "support (old) talk protocol"); +MODULE_PARM(ntalk, "i"); +MODULE_PARM_DESC(ntalk, "support ntalk protocol"); +MODULE_PARM(ntalk2, "i"); +MODULE_PARM_DESC(ntalk2, "support ntalk2 protocol"); +#endif + +#if 0 +#define DEBUGP printk +#define IP_NAT_TALK_DEBUG +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: Time out? --RR */ + +static int +mangle_packet(struct sk_buff **pskb, + struct ip_conntrack *ct, + u_int32_t newip, + u_int16_t port, + struct talk_addr *addr, + struct talk_addr *ctl_addr) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + size_t udplen = (*pskb)->len - iph->ihl * 4; + + /* Fortunately talk sends a structure with the address and + port in it. The size of the packet won't change. */ + + if (ctl_addr == NULL) { + /* response */ + if (addr->ta_addr == INADDR_ANY) + return 1; + DEBUGP("ip_nat_talk_mangle_packet: response orig %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(newip), ntohs(port)); + addr->ta_addr = newip; + addr->ta_port = port; + } else { + /* message */ + if (addr->ta_addr != INADDR_ANY) { + /* Change address inside packet to match way we're mapping + this connection. */ + DEBUGP("ip_nat_talk_mangle_packet: message orig addr %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip), + ntohs(addr->ta_port)); + addr->ta_addr = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + } + DEBUGP("ip_nat_talk_mangle_packet: message orig ctl_addr %u.%u.%u.%u:%u, inserting %u.%u.%u.%u:%u\n", + NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port), + NIPQUAD(newip), ntohs(port)); + ctl_addr->ta_addr = newip; + ctl_addr->ta_port = port; + } + + /* Fix checksums */ + (*pskb)->csum = csum_partial((char *)udph + sizeof(struct udphdr), udplen - sizeof(struct udphdr), 0); + udph->check = 0; + udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP, + csum_partial((char *)udph, sizeof(struct udphdr), (*pskb)->csum)); + + ip_send_check(iph); + return 1; +} + +static int talk_help_msg(struct ip_conntrack *ct, + struct sk_buff **pskb, + u_char type, + struct talk_addr *addr, + struct talk_addr *ctl_addr) +{ + u_int32_t newip; + u_int16_t port; + + unsigned int verdict = NF_ACCEPT; + + DEBUGP("ip_nat_talk_help_msg: addr: %u.%u.%u.%u:%u, ctl_addr: %u.%u.%u.%u:%u, type %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + NIPQUAD(ctl_addr->ta_addr), ntohs(ctl_addr->ta_port), + type); + + /* Change address inside packet to match way we're mapping + this connection. */ + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port; + DEBUGP("ip_nat_talk_help_msg: inserting: %u.%u.%u.%u:%u\n", + NIPQUAD(newip), ntohs(port)); + + if (!mangle_packet(pskb, ct, newip, port, addr, ctl_addr)) + verdict = NF_DROP; + + return verdict; +} + +static int talk_help_response(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct sk_buff **pskb, + u_char type, + u_char answer, + struct talk_addr *addr) +{ + u_int32_t newip; + u_int16_t port; + struct ip_conntrack_tuple t; + struct ip_ct_talk_expect *ct_talk_info; + + DEBUGP("ip_nat_talk_help_response: addr: %u.%u.%u.%u:%u, type %d answer %d\n", + NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), + type, answer); + + LOCK_BH(&ip_talk_lock); + ct_talk_info = &exp->help.exp_talk_info; + + if (!(answer == SUCCESS + && (type == LOOK_UP || type == ANNOUNCE) + && exp != NULL)) { + UNLOCK_BH(&ip_talk_lock); + return NF_ACCEPT; + } + + DEBUGP("ip_nat_talk_help_response: talkinfo port %u (%s)\n", + ntohs(ct_talk_info->port), + type == LOOK_UP ? "LOOK_UP" : "ANNOUNCE"); + + /* Change address inside packet to match way we're mapping + this connection. */ + newip = ct->tuplehash[type == LOOK_UP ? IP_CT_DIR_ORIGINAL : + IP_CT_DIR_REPLY].tuple.dst.ip; + /* We can read expect here without conntrack lock, since it's + only set in ip_conntrack_talk , with ip_talk_lock held + writable */ + t = exp->tuple; + t.dst.ip = newip; + + /* Try to get same port: if not, try to change it. */ + for (port = ntohs(ct_talk_info->port); port != 0; port++) { + if (type == LOOK_UP) + t.dst.u.tcp.port = htons(port); + else + t.dst.u.udp.port = htons(port); + + if (ip_conntrack_change_expect(exp, &t) == 0) { + DEBUGP("ip_nat_talk_help_response: using %u.%u.%u.%u:%u\n", NIPQUAD(newip), port); + break; + } + } + UNLOCK_BH(&ip_talk_lock); + + if (port == 0 || !mangle_packet(pskb, ct, newip, htons(port), addr, NULL)) + return NF_DROP; + + return NF_ACCEPT; +} + +static unsigned int talk_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb, + int talk_port) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + unsigned int udplen = (*pskb)->len - iph->ihl * 4; + char *data = (char *)udph + sizeof(struct udphdr); + int dir; + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + dir = CTINFO2DIR(ctinfo); + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("ip_nat_talk_help: Not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + return NF_ACCEPT; + } + DEBUGP("ip_nat_talk_help: dir %s at hook %s, %u.%u.%u.%u:%u->%u.%u.%u.%u:%u, talk port %d\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", + NIPQUAD(iph->saddr), ntohs(udph->source), + NIPQUAD(iph->daddr), ntohs(udph->dest), + talk_port); + + /* Because conntrack does not drop packets, checking must be repeated here... */ + if (talk_port == TALK_PORT) { + if (dir == IP_CT_DIR_ORIGINAL + && udplen == sizeof(struct udphdr) + sizeof(struct talk_msg)) + return talk_help_msg(ct, pskb, + ((struct talk_msg *)data)->type, + &(((struct talk_msg *)data)->addr), + &(((struct talk_msg *)data)->ctl_addr)); + else if (dir == IP_CT_DIR_REPLY + && udplen == sizeof(struct udphdr) + sizeof(struct talk_response)) + return talk_help_response(ct, exp, pskb, + ((struct talk_response *)data)->type, + ((struct talk_response *)data)->answer, + &(((struct talk_response *)data)->addr)); + else { + DEBUGP("ip_nat_talk_help: not talk %s, datalen %u != %u\n", + dir == IP_CT_DIR_ORIGINAL ? "message" : "response", + (unsigned)udplen - sizeof(struct udphdr), + dir == IP_CT_DIR_ORIGINAL ? sizeof(struct talk_msg) : sizeof(struct talk_response)); + return NF_DROP; + } + } else { + if (dir == IP_CT_DIR_ORIGINAL) { + if (ntalk + && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_msg) + && ((struct ntalk_msg *)data)->vers == NTALK_VERSION) + return talk_help_msg(ct, pskb, + ((struct ntalk_msg *)data)->type, + &(((struct ntalk_msg *)data)->addr), + &(((struct ntalk_msg *)data)->ctl_addr)); + else if (ntalk2 + && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_msg) + && ((struct ntalk2_msg *)data)->vers == NTALK2_VERSION + && udplen == sizeof(struct udphdr) + + sizeof(struct ntalk2_msg) + + ((struct ntalk2_msg *)data)->extended) + return talk_help_msg(ct, pskb, + ((struct ntalk2_msg *)data)->type, + &(((struct ntalk2_msg *)data)->addr), + &(((struct ntalk2_msg *)data)->ctl_addr)); + else { + DEBUGP("ip_nat_talk_help: not ntalk/ntalk2 message, datalen %u != %u or %u + max 256\n", + (unsigned)udplen - sizeof(struct udphdr), + sizeof(struct ntalk_msg), sizeof(struct ntalk2_msg)); + return NF_DROP; + } + } else { + if (ntalk + && udplen == sizeof(struct udphdr) + sizeof(struct ntalk_response) + && ((struct ntalk_response *)data)->vers == NTALK_VERSION) + return talk_help_response(ct, exp, pskb, + ((struct ntalk_response *)data)->type, + ((struct ntalk_response *)data)->answer, + &(((struct ntalk_response *)data)->addr)); + else if (ntalk2 + && udplen >= sizeof(struct udphdr) + sizeof(struct ntalk2_response) + && ((struct ntalk2_response *)data)->vers == NTALK2_VERSION) + return talk_help_response(ct, exp, pskb, + ((struct ntalk2_response *)data)->type, + ((struct ntalk2_response *)data)->answer, + &(((struct ntalk2_response *)data)->addr)); + else { + DEBUGP("ip_nat_talk_help: not ntalk/ntalk2 response, datalen %u != %u or %u + max 256\n", + (unsigned)udplen - sizeof(struct udphdr), + sizeof(struct ntalk_response), sizeof(struct ntalk2_response)); + return NF_DROP; + } + } + } +} + +static unsigned int help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + return talk_help(ct, exp, info, ctinfo, hooknum, pskb, TALK_PORT); +} + +static unsigned int nhelp(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + return talk_help(ct, exp, info, ctinfo, hooknum, pskb, NTALK_PORT); +} + +static unsigned int +talk_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info); + +static struct ip_nat_helper talk_helpers[2] = + { { { NULL, NULL }, + "talk", /* name */ + IP_NAT_HELPER_F_ALWAYS, /* flags */ + THIS_MODULE, /* module */ + { { 0, { .udp = { __constant_htons(TALK_PORT) } } }, /* tuple */ + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { .udp = { 0xFFFF } } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + help, /* helper */ + talk_nat_expected }, /* expectfn */ + { { NULL, NULL }, + "ntalk", /* name */ + IP_NAT_HELPER_F_ALWAYS, /* flags */ + THIS_MODULE, /* module */ + { { 0, { .udp = { __constant_htons(NTALK_PORT) } } }, /* tuple */ + { 0, { 0 }, IPPROTO_UDP } }, + { { 0, { .udp = { 0xFFFF } } }, /* mask */ + { 0, { 0 }, 0xFFFF } }, + nhelp, /* helper */ + talk_nat_expected } /* expectfn */ + }; + +static unsigned int +talk_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info) +{ + struct ip_nat_multi_range mr; + u_int32_t newdstip, newsrcip, newip; + u_int16_t port; + unsigned int ret; + + struct ip_conntrack *master = master_ct(ct); + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + + IP_NF_ASSERT(!(info->initialized & (1<master->help.exp_talk_info.port; + UNLOCK_BH(&ip_talk_lock); + + DEBUGP("ip_nat_talk_expected: dir %s at hook %s, ct %p, master %p\n", + CTINFO2DIR((*pskb)->nfct - ct->infos) == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", + ct, master); + + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + /* Callee client -> caller server */ +#ifdef IP_NAT_TALK_DEBUG + struct iphdr *iph = (*pskb)->nh.iph; + struct udphdr *udph = (void *)iph + iph->ihl * 4; + + DEBUGP("ip_nat_talk_expected: UDP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(udph->source), + NIPQUAD(iph->daddr), ntohs(udph->dest)); +#endif + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + DEBUGP("ip_nat_talk_expected: callee client -> caller server, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + } else { + /* Callee client -> caller client */ +#ifdef IP_NAT_TALK_DEBUG + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *)iph + iph->ihl * 4; + + DEBUGP("ip_nat_talk_expected: TCP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", + NIPQUAD(iph->saddr), ntohs(tcph->source), + NIPQUAD(iph->daddr), ntohs(tcph->dest)); +#endif + newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + DEBUGP("ip_nat_talk_expected: callee client -> caller client, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + } + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) + newip = newsrcip; + else + newip = newdstip; + + DEBUGP("ip_nat_talk_expected: IP to %u.%u.%u.%u, port %u\n", NIPQUAD(newip), ntohs(port)); + + mr.rangesize = 1; + /* We don't want to manip the per-protocol, just the IPs... */ + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + /* ... unless we're doing a MANIP_DST, in which case, make + sure we map to the correct port */ + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { + mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + mr.range[0].min = mr.range[0].max + = ((union ip_conntrack_manip_proto) + { .udp = { port } }); + } + ret = ip_nat_setup_info(ct, &mr, hooknum); + + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { + DEBUGP("talk_expected: setting NAT helper for %p\n", ct); + /* NAT expectfn called with ip_nat_lock write-locked */ + info->helper = &talk_helpers[htons(port) - TALK_PORT]; + } + return ret; +} + +static int __init init(void) +{ + int ret = 0; + + if (talk > 0) { + ret = ip_nat_helper_register(&talk_helpers[0]); + + if (ret != 0) + return ret; + } + if (ntalk > 0 || ntalk2 > 0) { + ret = ip_nat_helper_register(&talk_helpers[1]); + + if (ret != 0 && talk > 0) + ip_nat_helper_unregister(&talk_helpers[0]); + } + return ret; +} + +static void __exit fini(void) +{ + if (talk > 0) + ip_nat_helper_unregister(&talk_helpers[0]); + if (ntalk > 0 || ntalk2 > 0) + ip_nat_helper_unregister(&talk_helpers[1]); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_tftp.c linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_tftp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_nat_tftp.c 2003-11-26 21:43:31.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_nat_tftp.c 2003-12-10 23:13:21.271842272 +0100 @@ -164,8 +164,6 @@ ports[0] = TFTP_PORT; for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { - memset(&tftp[i], 0, sizeof(struct ip_nat_helper)); - tftp[i].tuple.dst.protonum = IPPROTO_UDP; tftp[i].tuple.src.u.udp.port = htons(ports[i]); tftp[i].mask.dst.protonum = 0xFFFF; diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_pool.c linux-2.6.0-test11/net/ipv4/netfilter/ip_pool.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_pool.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_pool.c 2003-12-10 23:13:39.982997744 +0100 @@ -0,0 +1,332 @@ +/* Kernel module for IP pool management */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DP printk +#else +#define DP(format, args...) +#endif + +MODULE_LICENSE("GPL"); + +#define NR_POOL 16 +static int nr_pool = NR_POOL;/* overwrite this when loading module */ + +struct ip_pool { + u_int32_t first_ip; /* host byte order, included in range */ + u_int32_t last_ip; /* host byte order, included in range */ + void *members; /* the bitmap proper */ + int nr_use; /* total nr. of tests through this */ + int nr_match; /* total nr. of matches through this */ + rwlock_t lock; +}; + +static struct ip_pool *POOL; + +static inline struct ip_pool *lookup(ip_pool_t index) +{ + if (index < 0 || index >= nr_pool) { + DP("ip_pool:lookup: bad index %d\n", index); + return 0; + } + return POOL+index; +} + +int ip_pool_match(ip_pool_t index, u_int32_t addr) +{ + struct ip_pool *pool = lookup(index); + int res = 0; + + if (!pool || !pool->members) + return 0; + read_lock_bh(&pool->lock); + if (pool->members) { + if (addr >= pool->first_ip && addr <= pool->last_ip) { + addr -= pool->first_ip; + if (test_bit(addr, pool->members)) { + res = 1; +#ifdef CONFIG_IP_POOL_STATISTICS + pool->nr_match++; +#endif + } + } +#ifdef CONFIG_IP_POOL_STATISTICS + pool->nr_use++; +#endif + } + read_unlock_bh(&pool->lock); + return res; +} + +static int pool_change(ip_pool_t index, u_int32_t addr, int isdel) +{ + struct ip_pool *pool; + int res = -1; + + pool = lookup(index); + if ( !pool || !pool->members + || addr < pool->first_ip || addr > pool->last_ip) + return -1; + read_lock_bh(&pool->lock); + if (pool->members && addr >= pool->first_ip && addr <= pool->last_ip) { + addr -= pool->first_ip; + res = isdel + ? (0 != test_and_clear_bit(addr, pool->members)) + : (0 != test_and_set_bit(addr, pool->members)); + } + read_unlock_bh(&pool->lock); + return res; +} + +int ip_pool_mod(ip_pool_t index, u_int32_t addr, int isdel) +{ + int res = pool_change(index,addr,isdel); + + if (!isdel) res = !res; + return res; +} + +static inline int bitmap_bytes(u_int32_t a, u_int32_t b) +{ + return 4*((((b-a+8)/8)+3)/4); +} + +static inline int poolbytes(ip_pool_t index) +{ + struct ip_pool *pool = lookup(index); + + return pool ? bitmap_bytes(pool->first_ip, pool->last_ip) : 0; +} + +static int setpool( + struct sock *sk, + int optval, + void *user, + unsigned int len +) { + struct ip_pool_request req; + + DP("ip_pool:setpool: optval=%d, user=%p, len=%d\n", optval, user, len); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (optval != SO_IP_POOL) + return -EBADF; + if (len != sizeof(req)) + return -EINVAL; + if (copy_from_user(&req, user, sizeof(req)) != 0) + return -EFAULT; + printk("obsolete op - upgrade your ippool(8) utility.\n"); + return -EINVAL; +} + +static int getpool( + struct sock *sk, + int optval, + void *user, + int *len +) { + struct ip_pool_request req; + struct ip_pool *pool; + ip_pool_t i; + int newbytes; + void *newmembers; + int res; + + DP("ip_pool:getpool: optval=%d, user=%p\n", optval, user); + if (!capable(CAP_NET_ADMIN)) + return -EINVAL; + if (optval != SO_IP_POOL) + return -EINVAL; + if (*len != sizeof(req)) { + return -EFAULT; + } + if (copy_from_user(&req, user, sizeof(req)) != 0) + return -EFAULT; + DP("ip_pool:getpool op=%d, index=%d\n", req.op, req.index); + if (req.op < IP_POOL_BAD001) { + printk("obsolete op - upgrade your ippool(8) utility.\n"); + return -EFAULT; + } + switch(req.op) { + case IP_POOL_HIGH_NR: + DP("ip_pool HIGH_NR\n"); + req.index = IP_POOL_NONE; + for (i=0; imembers) + return -EBADF; + req.addr = htonl(pool->first_ip); + req.addr2 = htonl(pool->last_ip); + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_USAGE: + DP("ip_pool USE\n"); + pool = lookup(req.index); + if (!pool) + return -EINVAL; + if (!pool->members) + return -EBADF; + req.addr = pool->nr_use; + req.addr2 = pool->nr_match; + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_TEST_ADDR: + DP("ip_pool TEST 0x%08x\n", req.addr); + pool = lookup(req.index); + if (!pool) + return -EINVAL; + res = 0; + read_lock_bh(&pool->lock); + if (!pool->members) { + DP("ip_pool TEST_ADDR no members in pool\n"); + res = -EBADF; + goto unlock_and_return_res; + } + req.addr = ntohl(req.addr); + if (req.addr < pool->first_ip) { + DP("ip_pool TEST_ADDR address < pool bounds\n"); + res = -ERANGE; + goto unlock_and_return_res; + } + if (req.addr > pool->last_ip) { + DP("ip_pool TEST_ADDR address > pool bounds\n"); + res = -ERANGE; + goto unlock_and_return_res; + } + req.addr = (0 != test_bit((req.addr - pool->first_ip), + pool->members)); + read_unlock_bh(&pool->lock); + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_FLUSH: + DP("ip_pool FLUSH not yet implemented.\n"); + return -EBUSY; + case IP_POOL_DESTROY: + DP("ip_pool DESTROY not yet implemented.\n"); + return -EBUSY; + case IP_POOL_INIT: + DP("ip_pool INIT 0x%08x-0x%08x\n", req.addr, req.addr2); + pool = lookup(req.index); + if (!pool) + return -EINVAL; + req.addr = ntohl(req.addr); + req.addr2 = ntohl(req.addr2); + if (req.addr > req.addr2) { + DP("ip_pool INIT bad ip range\n"); + return -EINVAL; + } + newbytes = bitmap_bytes(req.addr, req.addr2); + newmembers = kmalloc(newbytes, GFP_KERNEL); + if (!newmembers) { + DP("ip_pool INIT out of mem for %d bytes\n", newbytes); + return -ENOMEM; + } + memset(newmembers, 0, newbytes); + write_lock_bh(&pool->lock); + if (pool->members) { + DP("ip_pool INIT pool %d exists\n", req.index); + kfree(newmembers); + res = -EBUSY; + goto unlock_and_return_res; + } + pool->first_ip = req.addr; + pool->last_ip = req.addr2; + pool->nr_use = 0; + pool->nr_match = 0; + pool->members = newmembers; + write_unlock_bh(&pool->lock); + return 0; + case IP_POOL_ADD_ADDR: + DP("ip_pool ADD_ADDR 0x%08x\n", req.addr); + req.addr = pool_change(req.index, ntohl(req.addr), 0); + return copy_to_user(user, &req, sizeof(req)); + case IP_POOL_DEL_ADDR: + DP("ip_pool DEL_ADDR 0x%08x\n", req.addr); + req.addr = pool_change(req.index, ntohl(req.addr), 1); + return copy_to_user(user, &req, sizeof(req)); + default: + DP("ip_pool:getpool bad op %d\n", req.op); + return -EINVAL; + } + return -EINVAL; + +unlock_and_return_res: + if (pool) + read_unlock_bh(&pool->lock); + return res; +} + +static struct nf_sockopt_ops so_pool += { { NULL, NULL }, PF_INET, + SO_IP_POOL, SO_IP_POOL+1, &setpool, + SO_IP_POOL, SO_IP_POOL+1, &getpool, + 0, NULL }; + +MODULE_PARM(nr_pool, "i"); + +static int __init init(void) +{ + ip_pool_t i; + int res; + + if (nr_pool < 1) { + printk("ip_pool module init: bad nr_pool %d\n", nr_pool); + return -EINVAL; + } + POOL = kmalloc(nr_pool * sizeof(*POOL), GFP_KERNEL); + if (!POOL) { + printk("ip_pool module init: out of memory for nr_pool %d\n", + nr_pool); + return -ENOMEM; + } + for (i=0; ivalue > NF_MAX_VERDICT) + return -EINVAL; + + entry = ipq_find_dequeue_entry(id_cmp, vmsg->id); + if (entry == NULL) + return -ENOENT; + else { + int verdict = vmsg->value; + + if (vmsg->data_len && vmsg->data_len == len) + if (ipq_mangle_ipv4((ipq_verdict_msg_t *)vmsg, entry) < 0) + verdict = NF_DROP; + + /* set mark of associated skb */ + entry->skb->nfmark = vmsg->nfmark; + + ipq_issue_verdict(entry, verdict); + return 0; + } +} + + +static int ipq_receive_peer(struct ipq_peer_msg *pmsg, unsigned char type, unsigned int len) { @@ -438,6 +465,14 @@ status = ipq_set_verdict(&pmsg->msg.verdict, len - sizeof(*pmsg)); break; + case IPQM_VWMARK: + if (pmsg->msg.verdict.value > NF_MAX_VERDICT) + status = -EINVAL; + else + status = ipq_set_vwmark(&pmsg->msg.vwmark, + len - sizeof(*pmsg)); + break; + default: status = -EINVAL; } diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/iptable_filter.c linux-2.6.0-test11/net/ipv4/netfilter/iptable_filter.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/iptable_filter.c 2003-11-26 21:43:35.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/iptable_filter.c 2003-12-10 23:13:24.664326536 +0100 @@ -52,7 +52,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* FORWARD */ @@ -60,7 +60,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_OUT */ @@ -68,7 +68,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } } }, @@ -77,7 +77,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_error), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, { } }, "ERROR" diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/iptable_mangle.c linux-2.6.0-test11/net/ipv4/netfilter/iptable_mangle.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/iptable_mangle.c 2003-11-26 21:45:28.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/iptable_mangle.c 2003-12-10 23:13:24.665326384 +0100 @@ -69,7 +69,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_IN */ @@ -77,7 +77,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* FORWARD */ @@ -85,7 +85,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_OUT */ @@ -93,7 +93,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* POST_ROUTING */ @@ -101,7 +101,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, }, @@ -110,7 +110,7 @@ 0, sizeof(struct ipt_entry), sizeof(struct ipt_error), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, { } }, "ERROR" diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/iptable_raw.c linux-2.6.0-test11/net/ipv4/netfilter/iptable_raw.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/iptable_raw.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/iptable_raw.c 2003-12-10 23:13:24.665326384 +0100 @@ -0,0 +1,153 @@ +/* + * 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT . + * + * Copyright (C) 2003 Jozsef Kadlecsik + */ +#include +#include + +#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT)) + +/* Standard entry. */ +struct ipt_standard +{ + struct ipt_entry entry; + struct ipt_standard_target target; +}; + +struct ipt_error_target +{ + struct ipt_entry_target target; + char errorname[IPT_FUNCTION_MAXNAMELEN]; +}; + +struct ipt_error +{ + struct ipt_entry entry; + struct ipt_error_target target; +}; + +static struct +{ + struct ipt_replace repl; + struct ipt_standard entries[2]; + struct ipt_error term; +} initial_table __initdata += { { "raw", RAW_VALID_HOOKS, 3, + sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error), + { [NF_IP_PRE_ROUTING] 0, + [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, + { [NF_IP_PRE_ROUTING] 0, + [NF_IP_LOCAL_OUT] sizeof(struct ipt_standard) }, + 0, NULL, { } }, + { + /* PRE_ROUTING */ + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ipt_entry), + sizeof(struct ipt_standard), + 0, NULL, 0, { 0, 0 }, { } }, + { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } }, + /* LOCAL_OUT */ + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ipt_entry), + sizeof(struct ipt_standard), + 0, NULL, 0, { 0, 0 }, { } }, + { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } } + }, + /* ERROR */ + { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ipt_entry), + sizeof(struct ipt_error), + 0, NULL, 0, { 0, 0 }, { } }, + { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } }, + { } }, + "ERROR" + } + } +}; + +static struct ipt_table packet_raw = { + .name = "raw", + .table = &initial_table.repl, + .valid_hooks = RAW_VALID_HOOKS, + .lock = RW_LOCK_UNLOCKED, + .me = THIS_MODULE, +}; + +/* The work comes in here from netfilter.c. */ +static unsigned int +ipt_hook(unsigned int hook, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(pskb, hook, in, out, &packet_raw, NULL); +} + +/* 'raw' is the very first table. */ +static struct nf_hook_ops ipt_ops[] = { + { /* PRE_ROUTING hook */ + .hook = ipt_hook, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_PRE_ROUTING, + .priority = NF_IP_PRI_RAW, + }, + { /* LOCAL_OUT hook */ + .hook = ipt_hook, + .owner = THIS_MODULE, + .pf = PF_INET, + .hooknum = NF_IP_LOCAL_OUT, + .priority = NF_IP_PRI_RAW, + }, +}; + +static int __init init(void) +{ + int ret; + + /* Register table */ + ret = ipt_register_table(&packet_raw); + if (ret < 0) + return ret; + + /* Register hooks */ + ret = nf_register_hook(&ipt_ops[0]); + if (ret < 0) + goto cleanup_table; + + ret = nf_register_hook(&ipt_ops[1]); + if (ret < 0) + goto cleanup_hook0; + + return ret; + + cleanup_hook0: + nf_unregister_hook(&ipt_ops[0]); + cleanup_table: + ipt_unregister_table(&packet_raw); + + return ret; +} + +static void __exit fini(void) +{ + unsigned int i; + + for (i = 0; i < sizeof(ipt_ops)/sizeof(struct nf_hook_ops); i++) + nf_unregister_hook(&ipt_ops[i]); + + ipt_unregister_table(&packet_raw); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_DESCRIPTION("IPv4 raw table"); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ip_tables.c linux-2.6.0-test11/net/ipv4/netfilter/ip_tables.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ip_tables.c 2003-11-26 21:43:25.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ip_tables.c 2003-12-10 23:14:00.453885696 +0100 @@ -4,6 +4,10 @@ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling * Copyright (C) 2009-2002 Netfilter core team * + * 6 Mar 2002 Robert Olsson + * 17 Apr 2003 Chris Wilson + * - mark_source_chains speedup for complex chains + * * 19 Jan 2002 Harald Welte * - increase module usage count as soon as we have rules inside * a table @@ -11,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,8 +28,17 @@ #include #include +#include #include +static const char *hooknames[] = { + [NF_IP_PRE_ROUTING] "PREROUTING", + [NF_IP_LOCAL_IN] "INPUT", + [NF_IP_FORWARD] "FORWARD", + [NF_IP_LOCAL_OUT] "OUTPUT", + [NF_IP_POST_ROUTING] "POSTROUTING", +}; + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("IPv4 packet filter"); @@ -322,6 +336,12 @@ t = ipt_get_target(e); IP_NF_ASSERT(t->u.kernel.target); + + /* The packet traced and the rule isn't an unconditional return/END. */ + if (((*pskb)->nfcache & NFC_TRACE) && e->rulenum) { + nf_log_packet(AF_INET, hook, *pskb, in, out, "TRACE: %s/%s/%u ", + table->name, e->chainname, e->rulenum); + } /* Standard target? */ if (!t->u.kernel.target->target) { int v; @@ -474,6 +494,29 @@ return find_inlist_lock(&ipt_target, name, "ipt_", error, mutex); } +static inline int +find_error_target(struct ipt_entry *s, + struct ipt_entry *e, + char **chainname) +{ + struct ipt_entry_target *t; + static struct ipt_entry *found = NULL; + + if (s == e) { + if (!found) + return 0; + t = ipt_get_target(found); + if (strcmp(t->u.user.name, + IPT_ERROR_TARGET) == 0) { + *chainname = t->data; + return 1; + } + } else + found = s; + + return 0; +} + /* All zeroes == unconditional rule. */ static inline int unconditional(const struct ipt_ip *ip) @@ -493,6 +536,11 @@ mark_source_chains(struct ipt_table_info *newinfo, unsigned int valid_hooks) { unsigned int hook; + char *chainname = NULL; + u_int32_t rulenum; + + /* keep track of where we have been: */ + unsigned char *been = vmalloc(newinfo->size); /* No recursion; use packet counter to save back ptrs (reset to 0 as we leave), and comefrom to save source hook bitmask */ @@ -506,6 +554,9 @@ /* Set initial back pointer. */ e->counters.pcnt = pos; + memset(been, 0, newinfo->size); + rulenum = 1; + chainname = (char *) hooknames[hook]; for (;;) { struct ipt_standard_target *t @@ -514,10 +565,13 @@ if (e->comefrom & (1 << NF_IP_NUMHOOKS)) { printk("iptables: loop hook %u pos %u %08X.\n", hook, pos, e->comefrom); + vfree(been); return 0; } e->comefrom |= ((1 << hook) | (1 << NF_IP_NUMHOOKS)); + e->rulenum = rulenum++; + e->chainname = chainname; /* Unconditional return/END. */ if (e->target_offset == sizeof(struct ipt_entry) @@ -527,6 +581,10 @@ && unconditional(&e->ip)) { unsigned int oldpos, size; + /* Set unconditional rulenum to zero. */ + e->rulenum = 0; + e->counters.bcnt = 0; + /* Return: backtrack through the last big jump. */ do { @@ -552,6 +610,11 @@ (newinfo->entries + pos); } while (oldpos == pos + e->next_offset); + /* Restore chainname, rulenum. */ + chainname = e->chainname; + rulenum = e->counters.bcnt; + e->counters.bcnt = 0; + /* Move along one */ size = e->next_offset; e = (struct ipt_entry *) @@ -561,12 +624,27 @@ } else { int newpos = t->verdict; - if (strcmp(t->target.u.user.name, + if ( (pos < 0 || pos >= newinfo->size + || !been[pos]) + && strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0 && newpos >= 0) { /* This a jump; chase it. */ + if (pos >= 0 && pos < newinfo->size) + been[pos]++; duprintf("Jump rule %u -> %u\n", pos, newpos); + e->counters.bcnt = rulenum++; + rulenum = 1; + e = (struct ipt_entry *) + (newinfo->entries + newpos); + if (IPT_ENTRY_ITERATE(newinfo->entries, + newinfo->size, + find_error_target, + e, &chainname) == 0) { + printk("ip_tables: table screwed up!\n"); + return 0; + } } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; @@ -580,6 +658,7 @@ next: duprintf("Finished chain %u\n", hook); } + vfree(been); return 1; } diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_addrtype.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_addrtype.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_addrtype.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_addrtype.c 2003-12-10 23:13:51.092308872 +0100 @@ -0,0 +1,65 @@ +/* + * iptables module to match inet_addr_type() of an ip. + */ + +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); + +static inline int match_type(u_int32_t addr, u_int16_t mask) +{ + return !!(mask & (1 << inet_addr_type(addr))); +} + +static int match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, + int offset, const void *hdr, u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_addrtype_info *info = matchinfo; + const struct iphdr *iph = skb->nh.iph; + int ret = 1; + + if (info->source) + ret &= match_type(iph->saddr, info->source)^info->invert_source; + if (info->dest) + ret &= match_type(iph->daddr, info->dest)^info->invert_dest; + + return ret; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_addrtype_info))) { + printk(KERN_ERR "ipt_addrtype: invalid size (%u != %u)\n.", + matchsize, IPT_ALIGN(sizeof(struct ipt_addrtype_info))); + return 0; + } + + return 1; +} + +static struct ipt_match addrtype_match = { { NULL, NULL }, "addrtype", &match, + &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&addrtype_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&addrtype_match); + +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_condition.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_condition.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_condition.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_condition.c 2003-12-10 23:13:53.356964592 +0100 @@ -0,0 +1,256 @@ +/*-------------------------------------------*\ +| Netfilter Condition Module | +| | +| Description: This module allows firewall | +| rules to match using condition variables | +| stored in /proc files. | +| | +| Author: Stephane Ouellette 2002-10-22 | +| | +| | +| History: | +| 2003-02-10 Second version with improved | +| locking and simplified code. | +| | +| This software is distributed under the | +| terms of the GNU GPL. | +\*-------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include + + +#ifndef CONFIG_PROC_FS +#error "Proc file system support is required for this module" +#endif + + +MODULE_AUTHOR("Stephane Ouellette "); +MODULE_DESCRIPTION("Allows rules to match against condition variables"); +MODULE_LICENSE("GPL"); + + +struct condition_variable { + struct condition_variable *next; + struct proc_dir_entry *status_proc; + atomic_t refcount; + int enabled; /* TRUE == 1, FALSE == 0 */ +}; + + +static rwlock_t list_lock; +static struct condition_variable *head = NULL; +static struct proc_dir_entry *proc_net_condition = NULL; + + +static int +ipt_condition_read_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (offset == 0) { + *start = buffer; + buffer[0] = (var->enabled) ? '1' : '0'; + buffer[1] = '\n'; + return 2; + } + + *eof = 1; + return 0; +} + + +static int +ipt_condition_write_info(struct file *file, const char *buffer, + unsigned long length, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (length) { + /* Match only on the first character */ + switch (buffer[0]) { + case '0': + var->enabled = 0; + break; + case '1': + var->enabled = 1; + } + } + + return (int) length; +} + + +static int +match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, int offset, + const void *hdr, u_int16_t datalen, int *hotdrop) +{ + const struct condition_info *info = + (const struct condition_info *) matchinfo; + struct condition_variable *var; + int condition_status = 0; + + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + condition_status = var->enabled; + break; + } + } + + read_unlock(&list_lock); + + return condition_status ^ info->invert; +} + + + +static int +checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + struct condition_info *info = (struct condition_info *) matchinfo; + struct condition_variable *var, *newvar; + + if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) + return 0; + + /* The first step is to check if the condition variable already exists. */ + /* Here, a read lock is sufficient because we won't change the list */ + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + + /* At this point, we need to allocate a new condition variable */ + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); + + if (!newvar) + return -ENOMEM; + + /* Create the condition variable's proc file entry */ + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); + + if (!newvar->status_proc) { + /* + * There are two possibilities: + * 1- Another condition variable with the same name has been created, which is valid. + * 2- There was a memory allocation error. + */ + kfree(newvar); + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + return -ENOMEM; + } + + atomic_set(&newvar->refcount, 1); + newvar->enabled = 0; + newvar->status_proc->owner = THIS_MODULE; + newvar->status_proc->data = newvar; + wmb(); + newvar->status_proc->read_proc = ipt_condition_read_info; + newvar->status_proc->write_proc = ipt_condition_write_info; + + write_lock(&list_lock); + + newvar->next = head; + head = newvar; + + write_unlock(&list_lock); + + return 1; +} + + +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + struct condition_info *info = (struct condition_info *) matchinfo; + struct condition_variable *var, *prev = NULL; + + if (matchsize != IPT_ALIGN(sizeof(struct condition_info))) + return; + + write_lock(&list_lock); + + for (var = head; var && strcmp(info->name, var->status_proc->name); + prev = var, var = var->next); + + if (var && atomic_dec_and_test(&var->refcount)) { + if (prev) + prev->next = var->next; + else + head = var->next; + + write_unlock(&list_lock); + remove_proc_entry(var->status_proc->name, proc_net_condition); + kfree(var); + } else + write_unlock(&list_lock); +} + + +static struct ipt_match condition_match = { + .name = "condition", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + + +static int __init +init(void) +{ + int errorcode; + + rwlock_init(&list_lock); + proc_net_condition = proc_mkdir("ipt_condition", proc_net); + + if (proc_net_condition) { + errorcode = ipt_register_match(&condition_match); + + if (errorcode) + remove_proc_entry("ipt_condition", proc_net); + } else + errorcode = -EACCES; + + return errorcode; +} + + +static void __exit +fini(void) +{ + ipt_unregister_match(&condition_match); + remove_proc_entry("ipt_condition", proc_net); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_connlimit.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_connlimit.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_connlimit.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_connlimit.c 2003-12-10 23:13:26.811000192 +0100 @@ -0,0 +1,232 @@ +/* + * netfilter module to limit the number of parallel tcp + * connections per IP address. + * (c) 2000 Gerd Knorr + * Nov 2002: Martin Bene : + * only ignore TIME_WAIT or gone connections + * + * based on ... + * + * Kernel module to match connection tracking information. + * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 0 + +MODULE_LICENSE("GPL"); + +/* we'll save the tuples of all connections we care about */ +struct ipt_connlimit_conn +{ + struct list_head list; + struct ip_conntrack_tuple tuple; +}; + +struct ipt_connlimit_data { + spinlock_t lock; + struct list_head iphash[256]; +}; + +static int ipt_iphash(u_int32_t addr) +{ + int hash; + + hash = addr & 0xff; + hash ^= (addr >> 8) & 0xff; + hash ^= (addr >> 16) & 0xff; + hash ^= (addr >> 24) & 0xff; + return hash; +} + +static int count_them(struct ipt_connlimit_data *data, + u_int32_t addr, u_int32_t mask, + struct ip_conntrack *ct) +{ +#if DEBUG + const static char *tcp[] = { "none", "established", "syn_sent", "syn_recv", + "fin_wait", "time_wait", "close", "close_wait", + "last_ack", "listen" }; +#endif + int addit = 1, matches = 0; + struct ip_conntrack_tuple tuple; + struct ip_conntrack_tuple_hash *found; + struct ipt_connlimit_conn *conn; + struct list_head *hash,*lh; + + spin_lock(&data->lock); + tuple = ct->tuplehash[0].tuple; + hash = &data->iphash[ipt_iphash(addr & mask)]; + + /* check the saved connections */ + for (lh = hash->next; lh != hash; lh = lh->next) { + conn = list_entry(lh,struct ipt_connlimit_conn,list); + found = ip_conntrack_find_get(&conn->tuple,ct); + if (0 == memcmp(&conn->tuple,&tuple,sizeof(tuple)) && + found != NULL && + found->ctrack->proto.tcp.state != TCP_CONNTRACK_TIME_WAIT) { + /* Just to be sure we have it only once in the list. + We should'nt see tuples twice unless someone hooks this + into a table without "-p tcp --syn" */ + addit = 0; + } +#if DEBUG + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d %s\n", + ipt_iphash(addr & mask), + NIPQUAD(conn->tuple.src.ip), ntohs(conn->tuple.src.u.tcp.port), + NIPQUAD(conn->tuple.dst.ip), ntohs(conn->tuple.dst.u.tcp.port), + (NULL != found) ? tcp[found->ctrack->proto.tcp.state] : "gone"); +#endif + if (NULL == found) { + /* this one is gone */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + continue; + } + if (found->ctrack->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT) { + /* we don't care about connections which are + closed already -> ditch it */ + lh = lh->prev; + list_del(lh->next); + kfree(conn); + nf_conntrack_put(&found->ctrack->infos[0]); + continue; + } + if ((addr & mask) == (conn->tuple.src.ip & mask)) { + /* same source IP address -> be counted! */ + matches++; + } + nf_conntrack_put(&found->ctrack->infos[0]); + } + if (addit) { + /* save the new connection in our list */ +#if DEBUG + printk("ipt_connlimit [%d]: src=%u.%u.%u.%u:%d dst=%u.%u.%u.%u:%d new\n", + ipt_iphash(addr & mask), + NIPQUAD(tuple.src.ip), ntohs(tuple.src.u.tcp.port), + NIPQUAD(tuple.dst.ip), ntohs(tuple.dst.u.tcp.port)); +#endif + conn = kmalloc(sizeof(*conn),GFP_ATOMIC); + if (NULL == conn) + return -1; + memset(conn,0,sizeof(*conn)); + INIT_LIST_HEAD(&conn->list); + conn->tuple = tuple; + list_add(&conn->list,hash); + matches++; + } + spin_unlock(&data->lock); + return matches; +} + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_connlimit_info *info = matchinfo; + int connections, match; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (NULL == ct) { + printk("ipt_connlimit: Oops: invalid ct state ?\n"); + *hotdrop = 1; + return 0; + } + connections = count_them(info->data,skb->nh.iph->saddr,info->mask,ct); + if (-1 == connections) { + printk("ipt_connlimit: Hmm, kmalloc failed :-(\n"); + *hotdrop = 1; /* let's free some memory :-) */ + return 0; + } + match = (info->inverse) ? (connections <= info->limit) : (connections > info->limit); +#if DEBUG + printk("ipt_connlimit: src=%u.%u.%u.%u mask=%u.%u.%u.%u " + "connections=%d limit=%d match=%s\n", + NIPQUAD(skb->nh.iph->saddr), NIPQUAD(info->mask), + connections, info->limit, match ? "yes" : "no"); +#endif + + return match; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_connlimit_info *info = matchinfo; + int i; + + /* verify size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connlimit_info))) + return 0; + + /* refuse anything but tcp */ + if (ip->proto != IPPROTO_TCP) + return 0; + + /* init private data */ + info->data = kmalloc(sizeof(struct ipt_connlimit_data),GFP_KERNEL); + spin_lock_init(&(info->data->lock)); + for (i = 0; i < 256; i++) + INIT_LIST_HEAD(&(info->data->iphash[i])); + + return 1; +} + +static void destroy(void *matchinfo, unsigned int matchinfosize) +{ + struct ipt_connlimit_info *info = matchinfo; + struct ipt_connlimit_conn *conn; + struct list_head *hash; + int i; + + /* cleanup */ + for (i = 0; i < 256; i++) { + hash = &(info->data->iphash[i]); + while (hash != hash->next) { + conn = list_entry(hash->next,struct ipt_connlimit_conn,list); + list_del(hash->next); + kfree(conn); + } + } + kfree(info->data); +} + +static struct ipt_match connlimit_match += { { NULL, NULL }, "connlimit", &match, &check, &destroy, THIS_MODULE }; + +static int __init init(void) +{ + /* NULL if ip_conntrack not a module */ + if (ip_conntrack_module) + __MOD_INC_USE_COUNT(ip_conntrack_module); + return ipt_register_match(&connlimit_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&connlimit_match); + if (ip_conntrack_module) + __MOD_DEC_USE_COUNT(ip_conntrack_module); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_connmark.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_connmark.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_connmark.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_connmark.c 2003-12-10 23:13:54.582778240 +0100 @@ -0,0 +1,55 @@ +/* Kernel module to match connection mark values. */ +#include +#include + +#include +#include +#include + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_connmark_info *info = matchinfo; + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (!ct) + return 0; + + return ((ct->mark & info->mask) == info->mark) ^ info->invert; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info))) + return 0; + + return 1; +} + +static struct ipt_match connmark_match += { { NULL, NULL }, "connmark", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&connmark_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&connmark_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_CONNMARK.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_CONNMARK.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_CONNMARK.c 2003-12-10 23:13:54.583778088 +0100 @@ -0,0 +1,87 @@ +/* This is a module which is used for setting/remembering the mark field of + * an connection, or optionally restore it to the skb + */ +#include +#include +#include +#include + +#include +#include +#include + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_connmark_target_info *markinfo = targinfo; + + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); + if (ct) { + switch(markinfo->mode) { + case IPT_CONNMARK_SET: + ct->mark = markinfo->mark; + break; + case IPT_CONNMARK_SAVE: + ct->mark = (*pskb)->nfmark; + break; + case IPT_CONNMARK_RESTORE: + if (ct->mark != (*pskb)->nfmark) { + (*pskb)->nfmark = ct->mark; + (*pskb)->nfcache |= NFC_ALTERED; + } + break; + } + } + + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_connmark_target_info *matchinfo = targinfo; + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) { + printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_connmark_target_info))); + return 0; + } + + if (matchinfo->mode == IPT_CONNMARK_RESTORE) { + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + } + + return 1; +} + +static struct ipt_target ipt_connmark_reg += { { NULL, NULL }, "CONNMARK", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_connmark_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_connmark_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_conntrack.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_conntrack.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_conntrack.c 2003-11-26 21:45:34.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_conntrack.c 2003-12-10 23:13:24.664326536 +0100 @@ -29,7 +29,9 @@ #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) - if (ct) + if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW]) + statebit = IPT_CONNTRACK_STATE_UNTRACKED; + else if (ct) statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); else statebit = IPT_CONNTRACK_STATE_INVALID; diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_dstlimit.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_dstlimit.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_dstlimit.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_dstlimit.c 2003-12-10 23:13:27.869839224 +0100 @@ -0,0 +1,623 @@ +/* iptables match extension to limit the number of packets per second + * seperately for each destination. + * + * (C) 2003 by Harald Welte + * + * Development of this code was funded by Astaro AG, http://www.astaro.com/ + * + * based on ipt_limit.c by: + * Jérôme de Vivie + * Hervé Eychenne + * Rusty Russell + * + * The general idea is to create a hash table for every dstip and have a + * seperate limit counter per tuple. This way you can do something like 'limit + * the number of syn packets for each of my internal addresses. + * + * Ideally this would just be implemented as a general 'hash' match, which would + * allow us to attach any iptables target to it's hash buckets. But this is + * not possible in the current iptables architecture. As always, pkttables for + * 2.7.x will help ;) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) +#include +#include + +#include +#include + +/* FIXME: this is just for IP_NF_ASSERRT */ +#include + +#define MS2JIFFIES(x) ((x*HZ)/1000) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("iptables match for limiting per destination"); + +/* need to declare this at the top */ +static struct proc_dir_entry *dstlimit_procdir; +static struct file_operations dl_file_ops; + +/* hash table crap */ + +struct dsthash_dst { + u_int32_t src_ip; + u_int32_t dst_ip; + u_int16_t port; +}; + +struct dsthash_ent { + /* static / read-only parts in the beginning */ + struct list_head list; + struct dsthash_dst dst; + + /* modified structure members in the end */ + unsigned long expires; /* precalculated expiry time */ + struct { + unsigned long prev; /* last modification */ + u_int32_t credit; + u_int32_t credit_cap, cost; + } rateinfo; +}; + +struct ipt_dstlimit_htable { + struct ipt_dstlimit_info *minfo; /* public structure */ + + /* used internally */ + spinlock_t lock; /* lock for list_head */ + u_int32_t rnd; /* random seed for hash */ + struct timer_list timer; /* timer for gc */ + atomic_t count; /* number entries in table */ + + /* seq_file stuff */ + struct proc_dir_entry *pde; + + struct list_head hash[0]; /* hashtable itself */ +}; + +static kmem_cache_t *dstlimit_cachep; + +static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b) +{ + return (ent->dst.dst_ip == b->dst_ip + && ent->dst.port == b->port + && ent->dst.src_ip == b->src_ip); +} + +static inline u_int32_t +hash_dst(const struct ipt_dstlimit_htable *ht, const struct dsthash_dst *dst) +{ + return (jhash_3words(dst->dst_ip, dst->port, + dst->src_ip, ht->rnd) % ht->minfo->size); +} + +static inline struct dsthash_ent * +__dsthash_find(const struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst) +{ + struct dsthash_ent *ent; + u_int32_t hash = hash_dst(ht, dst); + MUST_BE_LOCKED(&ht->lock); + ent = LIST_FIND(&ht->hash[hash], dst_cmp, struct dsthash_ent *, dst); + return ent; +} + +/* allocate dsthash_ent, initialize dst, put in htable and lock it */ +static struct dsthash_ent * +__dsthash_alloc_init(struct ipt_dstlimit_htable *ht, struct dsthash_dst *dst) +{ + struct dsthash_ent *ent; + + /* initialize hash with random val at the time we allocate + * the first hashtable entry */ + if (!ht->rnd) + get_random_bytes(&ht->rnd, 4); + + if (ht->minfo->max && + atomic_read(&ht->count) >= ht->minfo->max) { + /* FIXME: do something. question is what.. */ + if (net_ratelimit()) + printk("max count of %u reached\n", ht->minfo->max); + return NULL; + } + + ent = kmem_cache_alloc(dstlimit_cachep, GFP_ATOMIC); + if (!ent) { + if (net_ratelimit()) + printk("Can't allocate dsthash_ent\n"); + return NULL; + } + + atomic_inc(&ht->count); + + ent->dst.dst_ip = dst->dst_ip; + ent->dst.port = dst->port; + ent->dst.src_ip = dst->src_ip; + + list_add(&ent->list, &ht->hash[hash_dst(ht, dst)]); + + return ent; +} + +static inline void +__dsthash_free(struct ipt_dstlimit_htable *ht, struct dsthash_ent *ent) +{ + MUST_BE_LOCKED(&ht->lock); + + list_del(&ent->list); + kmem_cache_free(dstlimit_cachep, ent); + atomic_dec(&ht->count); +} + +static void htable_gc(unsigned long htlong); + +static int htable_create(struct ipt_dstlimit_info *minfo) +{ + int i; + struct ipt_dstlimit_htable *hinfo; + + if (!minfo->size) { + minfo->size = (((num_physpages << PAGE_SHIFT) / 16384) + / sizeof(struct list_head)); + if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE)) + minfo->size = 8192; + if (minfo->size < 16) + minfo->size = 16; + } + if (!minfo->max) + minfo->max = 8 * minfo->size; + else if (minfo->max < minfo->size) + minfo->max = minfo->size; + + /* FIXME: don't use vmalloc() here or anywhere else -HW */ + hinfo = vmalloc(sizeof(struct ipt_dstlimit_htable) + + (sizeof(struct list_head) * minfo->size)); + if (!hinfo) { + printk(KERN_ERR "Unable to create ipt_dstlimit hash\n"); + return -1; + } + + for (i = 0; i < minfo->size; i++) + INIT_LIST_HEAD(&hinfo->hash[i]); + + minfo->hinfo = hinfo; + + hinfo->minfo = minfo; + atomic_set(&hinfo->count, 0); + hinfo->rnd = 0; + + hinfo->lock = SPIN_LOCK_UNLOCKED; + + hinfo->pde = create_proc_entry(minfo->name, 0, dstlimit_procdir); + if (!hinfo->pde) { + vfree(hinfo); + return -1; + } + hinfo->pde->proc_fops = &dl_file_ops; + hinfo->pde->data = hinfo; + + init_timer(&hinfo->timer); + hinfo->timer.expires = jiffies + MS2JIFFIES(minfo->gc_interval); + hinfo->timer.data = (unsigned long )hinfo; + hinfo->timer.function = htable_gc; + add_timer(&hinfo->timer); + + return 0; +} + +static int select_all(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he) +{ + return 1; +} + +static int select_gc(struct ipt_dstlimit_htable *ht, struct dsthash_ent *he) +{ + return (jiffies >= he->expires); +} + +static void htable_selective_cleanup(struct ipt_dstlimit_htable *ht, + int (*select)(struct ipt_dstlimit_htable *ht, + struct dsthash_ent *he)) +{ + int i; + + IP_NF_ASSERT(ht->minfo->size && ht->minfo->max); + + /* lock hash table and iterate over it */ + LOCK_BH(&ht->lock); + for (i = 0; i < ht->minfo->size; i++) { + struct dsthash_ent *dh, *n; + list_for_each_entry_safe(dh, n, &ht->hash[i], list) { + if ((*select)(ht, dh)) + __dsthash_free(ht, dh); + } + } + UNLOCK_BH(&ht->lock); +} + +/* hash table garbage collector, run by timer */ +static void htable_gc(unsigned long htlong) +{ + struct ipt_dstlimit_htable *ht = (struct ipt_dstlimit_htable *)htlong; + + htable_selective_cleanup(ht, select_gc); + + /* re-add the timer accordingly */ + ht->timer.expires = jiffies + MS2JIFFIES(ht->minfo->gc_interval); + add_timer(&ht->timer); +} + +/* The algorithm used is the Simple Token Bucket Filter (TBF) + * see net/sched/sch_tbf.c in the linux source tree + */ + +/* Rusty: This is my (non-mathematically-inclined) understanding of + this algorithm. The `average rate' in jiffies becomes your initial + amount of credit `credit' and the most credit you can ever have + `credit_cap'. The `peak rate' becomes the cost of passing the + test, `cost'. + + `prev' tracks the last packet hit: you gain one credit per jiffy. + If you get credit balance more than this, the extra credit is + discarded. Every time the match passes, you lose `cost' credits; + if you don't have that many, the test fails. + + See Alexey's formal explanation in net/sched/sch_tbf.c. + + To get the maximum range, we multiply by this factor (ie. you get N + credits per jiffy). We want to allow a rate as low as 1 per day + (slowest userspace tool allows), which means + CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie. +*/ +#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) + +/* Repeated shift and or gives us all 1s, final shift and add 1 gives + * us the power of 2 below the theoretical max, so GCC simply does a + * shift. */ +#define _POW2_BELOW2(x) ((x)|((x)>>1)) +#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) +#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) +#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) +#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) +#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) + +#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) + +/* Precision saver. */ +static inline u_int32_t +user2credits(u_int32_t user) +{ + /* If multiplying would overflow... */ + if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) + /* Divide first. */ + return (user / IPT_DSTLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; + + return (user * HZ * CREDITS_PER_JIFFY) / IPT_DSTLIMIT_SCALE; +} + +static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now) +{ + dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now)) + * CREDITS_PER_JIFFY; + if (dh->rateinfo.credit > dh->rateinfo.credit_cap) + dh->rateinfo.credit = dh->rateinfo.credit_cap; +} + +static int +dstlimit_match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + struct ipt_dstlimit_info *r = + ((struct ipt_dstlimit_info *)matchinfo)->u.master; + unsigned long now = jiffies; + struct dsthash_ent *dh; + struct dsthash_dst dst; + + memset(&dst, 0, sizeof(dst)); + + /* dest ip is always in hash */ + dst.dst_ip = skb->nh.iph->daddr; + + /* source ip only if respective hashmode, otherwise set to + * zero */ + if (r->mode & IPT_DSTLIMIT_HASH_SIP) + dst.src_ip = skb->nh.iph->saddr; + + /* dest port only if respective mode */ + if (r->mode & IPT_DSTLIMIT_HASH_DPT) { + switch (skb->nh.iph->protocol) { + struct tcphdr *th; + struct udphdr *uh; + case IPPROTO_TCP: + th = (void *)skb->nh.iph+skb->nh.iph->ihl*4; + dst.port = th->dest; + break; + case IPPROTO_UDP: + uh = (void *)skb->nh.iph+skb->nh.iph->ihl*4; + dst.port = uh->dest; + break; + default: + break; + } + } + + LOCK_BH(&r->hinfo->lock); + dh = __dsthash_find(r->hinfo, &dst); + if (!dh) { + dh = __dsthash_alloc_init(r->hinfo, &dst); + + if (!dh) { + /* enomem... don't match == DROP */ + if (net_ratelimit()) + printk("%s: ENOMEM\n", __FUNCTION__); + UNLOCK_BH(&r->hinfo->lock); + return 0; + } + + dh->expires = jiffies + MS2JIFFIES(r->expire); + + dh->rateinfo.prev = jiffies; + dh->rateinfo.credit = user2credits(r->avg * r->burst); + dh->rateinfo.credit_cap = user2credits(r->avg * r->burst); + dh->rateinfo.cost = user2credits(r->avg); + + UNLOCK_BH(&r->hinfo->lock); + return 0; + } + + /* update expiration timeout */ + dh->expires = now + MS2JIFFIES(r->expire); + + rateinfo_recalc(dh, now); + if (dh->rateinfo.credit >= dh->rateinfo.cost) { + /* We're underlimit. */ + dh->rateinfo.credit -= dh->rateinfo.cost; + UNLOCK_BH(&r->hinfo->lock); + return 1; + } + + UNLOCK_BH(&r->hinfo->lock); + + /* default case: we're overlimit, thus don't match */ + return 0; +} + +static int +dstlimit_checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_dstlimit_info *r = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_dstlimit_info))) + return 0; + + /* Check for overflow. */ + if (r->burst == 0 + || user2credits(r->avg * r->burst) < user2credits(r->avg)) { + printk("Overflow in ipt_dstlimit, try lower: %u/%u\n", + r->avg, r->burst); + return 0; + } + + if (r->mode == 0 + || r->mode > (IPT_DSTLIMIT_HASH_DPT + |IPT_DSTLIMIT_HASH_DIP + |IPT_DSTLIMIT_HASH_SIP)) + return 0; + + if (!r->gc_interval) + return 0; + + if (!r->expire) + return 0; + + if (htable_create(r) != 0) { + printk("Unable to create dstlimit htable\n"); + return 0; + } + + /* Ugly hack: For SMP, we only want to use one set */ + r->u.master = r; + + return 1; +} + +static void +dstlimit_destroy(void *matchinfo, unsigned int matchsize) +{ + struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *) matchinfo; + + r = r->u.master; + + /* remove timer, if it is pending */ + if (timer_pending(&r->hinfo->timer)) + del_timer(&r->hinfo->timer); + + /* remove proc entry */ + remove_proc_entry(r->name, dstlimit_procdir); + + htable_selective_cleanup(r->hinfo, select_all); + vfree(&r->hinfo); +} + +static struct ipt_match ipt_dstlimit = { + .list = { .prev = NULL, .next = NULL }, + .name = "dstlimit", + .match = dstlimit_match, + .checkentry = dstlimit_checkentry, + .destroy = dstlimit_destroy, + .me = THIS_MODULE +}; + +/* PROC stuff */ + +static void *dl_seq_start(struct seq_file *s, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct ipt_dstlimit_htable *htable = pde->data; + unsigned int *bucket; + + LOCK_BH(&htable->lock); + if (*pos >= htable->minfo->size) + return NULL; + + bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL); + if (!bucket) + return ERR_PTR(-ENOMEM); + + *bucket = *pos; + return bucket; +} + +static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = s->private; + struct ipt_dstlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + + *pos = ++(*bucket); + if (*pos >= htable->minfo->size) { + kfree(v); + return NULL; + } + return bucket; +} + +static void dl_seq_stop(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct ipt_dstlimit_htable *htable = pde->data; + + UNLOCK_BH(&htable->lock); +} + +static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s) +{ + /* recalculate to show accurate numbers */ + rateinfo_recalc(ent, jiffies); + + return seq_printf(s, "%ld %u.%u.%u.%u->%u.%u.%u.%u:%u %u %u %u\n", + (ent->expires - jiffies)/HZ, + NIPQUAD(ent->dst.src_ip), + NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.port), + ent->rateinfo.credit, ent->rateinfo.credit_cap, + ent->rateinfo.cost); +} + +static int dl_seq_show(struct seq_file *s, void *v) +{ + struct proc_dir_entry *pde = s->private; + struct ipt_dstlimit_htable *htable = pde->data; + unsigned int *bucket = (unsigned int *)v; + + if (LIST_FIND_W(&htable->hash[*bucket], dl_seq_real_show, + struct dsthash_ent *, s)) { + /* buffer was filled and unable to print that tuple */ + return 1; + } + return 0; +} + +static struct seq_operations dl_seq_ops = { + .start = dl_seq_start, + .next = dl_seq_next, + .stop = dl_seq_stop, + .show = dl_seq_show +}; + +static int dl_proc_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &dl_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +} + +static struct file_operations dl_file_ops = { + .owner = THIS_MODULE, + .open = dl_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release +}; + +static int init_or_fini(int fini) +{ + int ret = 0; + + if (fini) + goto cleanup; + + if (ipt_register_match(&ipt_dstlimit)) { + ret = -EINVAL; + goto cleanup_nothing; + } + + /* FIXME: do we really want HWCACHE_ALIGN since our objects are + * quite small ? */ + dstlimit_cachep = kmem_cache_create("ipt_dstlimit", + sizeof(struct dsthash_ent), 0, + SLAB_HWCACHE_ALIGN, NULL, NULL); + if (!dstlimit_cachep) { + printk(KERN_ERR "Unable to create ipt_dstlimit slab cache\n"); + ret = -ENOMEM; + goto cleanup_unreg_match; + } + + dstlimit_procdir = proc_mkdir("ipt_dstlimit", proc_net); + if (!dstlimit_procdir) { + printk(KERN_ERR "Unable to create proc dir entry\n"); + ret = -ENOMEM; + goto cleanup_free_slab; + } + + return ret; + +cleanup: + remove_proc_entry("ipt_dstlimit", proc_net); +cleanup_free_slab: + kmem_cache_destroy(dstlimit_cachep); +cleanup_unreg_match: + ipt_unregister_match(&ipt_dstlimit); +cleanup_nothing: + return ret; + +} + +static int __init init(void) +{ + return init_or_fini(0); +} + +static void __exit fini(void) +{ + init_or_fini(1); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_fuzzy.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_fuzzy.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_fuzzy.c 2003-12-10 23:13:30.017512728 +0100 @@ -0,0 +1,190 @@ +/* + * This module implements a simple TSK FLC + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims + * to limit , in an adaptive and flexible way , the packet rate crossing + * a given stream . It serves as an initial and very simple (but effective) + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks. + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior" + * into our code in a precise , adaptive and efficient manner. + * The goal is very similar to that of "limit" match , but using techniques of + * Fuzzy Control , that allow us to shape the transfer functions precisely , + * avoiding over and undershoots - and stuff like that . + * + * + * 2002-08-10 Hime Aguiar e Oliveira Jr. : Initial version. + * 2002-08-17 : Changed to eliminate floating point operations . + * 2002-08-23 : Coding style changes . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH + Expressed in percentage +*/ + +#define PAR_LOW 1/100 +#define PAR_HIGH 1 + +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ; + +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior "); +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module"); +MODULE_LICENSE("GPL"); + +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi) +{ + if (tx >= maxi) return 100; + + if (tx <= mini) return 0; + + return ( (100*(tx-mini)) / (maxi-mini) ) ; +} + +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi) +{ + if (tx <= mini) return 100; + + if (tx >= maxi) return 0; + + return ( (100*( maxi - tx )) / ( maxi - mini ) ) ; + +} + +static int +ipt_fuzzy_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* From userspace */ + + struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo; + + u_int8_t random_number; + unsigned long amount ; + u_int8_t howhigh , howlow ; + + + spin_lock_bh(&fuzzy_lock) ; /* Rise the lock */ + + info->bytes_total += pskb->len ; + info->packets_total++ ; + + info->present_time = jiffies ; + + if ( info->present_time >= info->previous_time ) + amount = info->present_time - info->previous_time ; + else { + /* There was a transition : I choose to re-sample + and keep the old acceptance rate... + */ + + amount = 0 ; + info->previous_time = info->present_time ; + info->bytes_total = info->packets_total = 0; + }; + + if ( amount > HZ/10 ) /* More than 100 ms elapsed ... */ + { + + info->mean_rate = (u_int32_t) ( ( HZ * info->packets_total ) \ + / amount ) ; + + info->previous_time = info->present_time ; + info->bytes_total = info->packets_total = 0 ; + + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate); + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate); + + info->acceptance_rate = (u_int8_t) \ + ( howhigh*PAR_LOW + PAR_HIGH*howlow ) ; + + /* In fact , the above defuzzification would require a denominator + proportional to (howhigh+howlow) but , in this particular case , + that expression is constant . + An imediate consequence is that it isn't necessary to call + both mf_high and mf_low - but to keep things understandable , + I did so . + */ + + } + + spin_unlock_bh(&fuzzy_lock) ; /* Release the lock */ + + + if ( info->acceptance_rate < 100 ) + { + get_random_bytes((void *)(&random_number), 1); + + /* If within the acceptance , it can pass => don't match */ + if ( random_number <= (255 * info->acceptance_rate) / 100 ) + return 0 ; + else + return 1; /* It can't pass ( It matches ) */ + } ; + + return 0; /* acceptance_rate == 100 % => Everything passes ... */ + +} + +static int +ipt_fuzzy_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + + const struct ipt_fuzzy_info *info = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) { + printk("ipt_fuzzy: matchsize %u != %u\n", matchsize, + IPT_ALIGN(sizeof(struct ipt_fuzzy_info))); + return 0; + } + +if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE) + || (info->minimum_rate >= info->maximum_rate )) + { + printk("ipt_fuzzy: BAD limits , please verify !!!\n"); + return 0; + } + + return 1; +} + +static struct ipt_match ipt_fuzzy_reg = { + {NULL, NULL}, + "fuzzy", + ipt_fuzzy_match, + ipt_fuzzy_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_match(&ipt_fuzzy_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_fuzzy_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_IPMARK.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_IPMARK.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_IPMARK.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_IPMARK.c 2003-12-10 23:13:59.369050616 +0100 @@ -0,0 +1,88 @@ +/* This is a module which is used for setting the NFMARK field of an skb. */ +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Grzegorz Janoszka "); +MODULE_DESCRIPTION("IP tables IPMARK: mark based on ip address"); +MODULE_LICENSE("GPL"); + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_ipmark_target_info *ipmarkinfo = targinfo; + + struct iphdr *iph = (*pskb)->nh.iph; + + unsigned long mark; + char *a, t; + + if(ipmarkinfo->addr == IPT_IPMARK_SRC) + mark = (unsigned long) iph->saddr; + else + mark = (unsigned long) iph->daddr; + +// mark has ip address in little indian, we have to change the byte order: + a = (char *) &mark; + t = *a; *a=*(a+3); *(a+3)=t; + t=*(a+1); *(a+1)=*(a+2); *(a+2)=t; + + mark &= ipmarkinfo->andmask; + mark |= ipmarkinfo->ormask; + + if((*pskb)->nfmark != mark) { + (*pskb)->nfmark = mark; + (*pskb)->nfcache |= NFC_ALTERED; + } + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ipmark_target_info))) { + printk(KERN_WARNING "IPMARK: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_ipmark_target_info))); + return 0; + } + + if (strcmp(tablename, "mangle") != 0) { + printk(KERN_WARNING "IPMARK: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_ipmark_reg += { { NULL, NULL }, "IPMARK", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_ipmark_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_ipmark_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ipv4options.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_ipv4options.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ipv4options.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_ipv4options.c 2003-12-10 23:13:32.270170272 +0100 @@ -0,0 +1,170 @@ +/* + This is a module which is used to match ipv4 options. + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 11-mars-2001 Fabrice MARIE : initial development. + 12-july-2001 Fabrice MARIE : added router-alert otions matching. Fixed a bug with no-srr + 12-august-2001 Imran Patel : optimization of the match. + 18-november-2001 Fabrice MARIE : added [!] 'any' option match. +*/ + +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */ + const struct iphdr *iph = skb->nh.iph; + const struct ip_options *opt; + + if (iph->ihl * 4 == sizeof(struct iphdr)) { + /* No options, so we match only the "DONTs" and the "IGNOREs" */ + + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) || + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) || + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) || + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT)) + return 0; + return 1; + } + else { + if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) + /* there are options, and we don't need to care which one */ + return 1; + else { + if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) + /* there are options but we don't want any ! */ + return 0; + } + } + + opt = &(IPCB(skb)->opt); + + /* source routing */ + if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) { + if (!((opt->srr) & (opt->is_strictroute))) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) { + if (!((opt->srr) & (!opt->is_strictroute))) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) { + if (opt->srr) + return 0; + } + /* record route */ + if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) { + if (!opt->rr) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) { + if (opt->rr) + return 0; + } + /* timestamp */ + if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) { + if (!opt->ts) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) { + if (opt->ts) + return 0; + } + /* router-alert option */ + if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) { + if (!opt->router_alert) + return 0; + } + else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) { + if (opt->router_alert) + return 0; + } + + /* we match ! */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + const struct ipt_ipv4options_info *info = matchinfo; /* match info for rule */ + /* Check the size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info))) + return 0; + /* Now check the coherence of the data ... */ + if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) && + (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) || + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT))) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) && + (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) || + ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) || + ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) || + ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT))) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) && + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) + return 0; /* cannot match in the same time loose and strict source routing */ + if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) || + ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP)) + return 0; /* opposites */ + if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) && + ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT)) + return 0; /* opposites */ + + /* everything looks ok. */ + return 1; +} + +static struct ipt_match ipv4options_match += { { NULL, NULL }, "ipv4options", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + printk("ipt_ipv4options loading\n"); + return ipt_register_match(&ipv4options_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipv4options_match); + printk("ipt_ipv4options unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_IPV4OPTSSTRIP.c 2003-12-10 23:13:33.336008240 +0100 @@ -0,0 +1,84 @@ +/** + * Strip all IP options in the IP packet header. + * + * (C) 2001 by Fabrice MARIE + * This software is distributed under GNU GPL v2, 1991 + */ + +#include +#include +#include +#include + +#include + +MODULE_AUTHOR("Fabrice MARIE "); +MODULE_DESCRIPTION("Strip all options in IPv4 packets"); +MODULE_LICENSE("GPL"); + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct sk_buff *skb = (*pskb); + struct ip_options * opt; + unsigned char * optiph = skb->nh.raw; + int l = ((struct ip_options *)(&(IPCB(skb)->opt)))->optlen; + + + /* if no options in packet then nothing to clear. */ + if (iph->ihl * 4 == sizeof(struct iphdr)) + return IPT_CONTINUE; + + /* else clear all options */ + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + memset(optiph+sizeof(struct iphdr), IPOPT_NOOP, l); + opt = &(IPCB(skb)->opt); + opt->is_data = 0; + opt->optlen = l; + + skb->nfcache |= NFC_ALTERED; + + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (strcmp(tablename, "mangle")) { + printk(KERN_WARNING "IPV4OPTSSTRIP: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + /* nothing else to check because no parameters */ + return 1; +} + +static struct ipt_target ipt_ipv4optsstrip_reg += { { NULL, NULL }, "IPV4OPTSSTRIP", target, checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_ipv4optsstrip_reg)) + return -EINVAL; + printk("ipt_IPV4OPTSSTRIP loaded\n"); + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_ipv4optsstrip_reg); + printk("ipt_IPV4OPTSSTRIP unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_LOG.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_LOG.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_LOG.c 2003-11-26 21:45:28.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_LOG.c 2003-12-10 23:13:22.346678872 +0100 @@ -4,12 +4,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -17,6 +19,10 @@ MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("iptables syslog logging module"); +static unsigned int nflog = 1; +MODULE_PARM(nflog, "i"); +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); + #if 0 #define DEBUGP printk #else @@ -315,28 +321,25 @@ /* maxlen = 230+ 91 + 230 + 252 = 803 */ } -static unsigned int -ipt_log_target(struct sk_buff **pskb, +static void +ipt_log_packet(unsigned int hooknum, + const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, - unsigned int hooknum, - const void *targinfo, - void *userinfo) + const struct ipt_log_info *loginfo, + const char *level_string, + const char *prefix) { - const struct ipt_log_info *loginfo = targinfo; - char level_string[4] = "< >"; - - level_string[1] = '0' + (loginfo->level % 8); spin_lock_bh(&log_lock); printk(level_string); printk("%sIN=%s OUT=%s ", - loginfo->prefix, + prefix == NULL ? loginfo->prefix : prefix, in ? in->name : "", out ? out->name : ""); #ifdef CONFIG_BRIDGE_NETFILTER - if ((*pskb)->nf_bridge) { - struct net_device *physindev = (*pskb)->nf_bridge->physindev; - struct net_device *physoutdev = (*pskb)->nf_bridge->physoutdev; + if (skb->nf_bridge) { + struct net_device *physindev = skb->nf_bridge->physindev; + struct net_device *physoutdev = skb->nf_bridge->physoutdev; if (physindev && in != physindev) printk("PHYSIN=%s ", physindev->name); @@ -348,25 +351,56 @@ if (in && !out) { /* MAC logging for input chain only. */ printk("MAC="); - if ((*pskb)->dev && (*pskb)->dev->hard_header_len - && (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) { + if (skb->dev && skb->dev->hard_header_len + && skb->mac.raw != (void*)skb->nh.iph) { int i; - unsigned char *p = (*pskb)->mac.raw; - for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++) + unsigned char *p = skb->mac.raw; + for (i = 0; i < skb->dev->hard_header_len; i++,p++) printk("%02x%c", *p, - i==(*pskb)->dev->hard_header_len - 1 + i==skb->dev->hard_header_len - 1 ? ' ':':'); } else printk(" "); } - dump_packet(loginfo, *pskb, 0); + dump_packet(loginfo, skb, 0); printk("\n"); spin_unlock_bh(&log_lock); +} + +static unsigned int +ipt_log_target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, + void *userinfo) +{ + const struct ipt_log_info *loginfo = targinfo; + char level_string[4] = "< >"; + + level_string[1] = '0' + (loginfo->level % 8); + ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL); return IPT_CONTINUE; } +static void +ipt_logfn(unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const char *prefix) +{ + struct ipt_log_info loginfo = { + .level = 0, + .logflags = IPT_LOG_MASK, + .prefix = "" + }; + + ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix); +} + static int ipt_log_checkentry(const char *tablename, const struct ipt_entry *e, void *targinfo, @@ -406,12 +440,17 @@ { if (ipt_register_target(&ipt_log_reg)) return -EINVAL; + if (nflog) + nf_log_register(PF_INET, &ipt_logfn); return 0; } static void __exit fini(void) { + if (nflog) + nf_log_unregister(PF_INET, &ipt_logfn); + ipt_unregister_target(&ipt_log_reg); } diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_mark.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_mark.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_mark.c 2003-11-26 21:46:13.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_mark.c 2003-12-10 23:14:21.807639432 +0100 @@ -17,9 +17,15 @@ int offset, int *hotdrop) { - const struct ipt_mark_info *info = matchinfo; + const struct ipt_mark_info *info = (struct ipt_mark_info *)matchinfo; - return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; + if (info->bit_op == IPT_MARK_BIT_OP_NONE) + return (skb->nfmark == info->mark) ^ info->invert; + else + if (info->bit_op == IPT_MARK_BIT_OP_AND) + return ((skb->nfmark & info->mask) == info->mark) ^ info->invert; + else + return ((skb->nfmark | info->mask) == info->mark) ^ info->invert; } static int diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_mport.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_mport.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_mport.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_mport.c 2003-12-10 23:13:34.441840128 +0100 @@ -0,0 +1,112 @@ +/* Kernel module to match one of a list of TCP/UDP ports: ports are in + the same place so we can treat them as equal. */ +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); + +#if 0 +#define duprintf(format, args...) printk(format , ## args) +#else +#define duprintf(format, args...) +#endif + +/* Returns 1 if the port is matched by the test, 0 otherwise. */ +static inline int +ports_match(const struct ipt_mport *minfo, u_int16_t src, u_int16_t dst) +{ + unsigned int i; + unsigned int m; + u_int16_t pflags = minfo->pflags; + for (i=0, m=1; iports[i] == 65535) + return 0; + + s = minfo->ports[i]; + + if (pflags & m) { + e = minfo->ports[++i]; + m <<= 1; + } else + e = s; + + if (minfo->flags & IPT_MPORT_SOURCE + && src >= s && src <= e) + return 1; + + if (minfo->flags & IPT_MPORT_DESTINATION + && dst >= s && dst <= e) + return 1; + } + + return 0; +} + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct udphdr *udp = hdr; + const struct ipt_mport *minfo = matchinfo; + + /* Must be big enough to read ports. */ + if (offset == 0 && datalen < sizeof(struct udphdr)) { + /* We've been asked to examine this packet, and we + can't. Hence, no choice but to drop. */ + duprintf("ipt_mport:" + " Dropping evil offset=0 tinygram.\n"); + *hotdrop = 1; + return 0; + } + + /* Must not be a fragment. */ + return !offset + && ports_match(minfo, ntohs(udp->source), ntohs(udp->dest)); +} + +/* Called when user tries to insert an entry of this type. */ +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_mport))) + return 0; + + /* Must specify proto == TCP/UDP, no unknown flags or bad count */ + return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) + && !(ip->invflags & IPT_INV_PROTO) + && matchsize == IPT_ALIGN(sizeof(struct ipt_mport)); +} + +static struct ipt_match mport_match += { { NULL, NULL }, "mport", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&mport_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&mport_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_NETLINK.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_NETLINK.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_NETLINK.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_NETLINK.c 2003-12-10 23:13:35.507678096 +0100 @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Gianni Tedesco "); +MODULE_DESCRIPTION("Provides iptables NETLINK target similar to ipchains -o"); +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +static struct sock *ipfwsk; + +static unsigned int ipt_netlink_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct ipt_nldata *nld = (struct ipt_nldata *)targinfo; + struct iphdr *ip = (*pskb)->nh.iph; + struct sk_buff *outskb; + struct netlink_t nlhdr; + size_t len=0; + + /* Allocate a socket buffer */ + if ( MASK(nld->flags, USE_SIZE) ) + len = nld->size+sizeof(nlhdr); + else + len = ntohs(ip->tot_len)+sizeof(nlhdr); + + outskb=alloc_skb(len, GFP_ATOMIC); + + if (outskb) { + nlhdr.len=len; + + if ( MASK(nld->flags, USE_MARK) ) + nlhdr.mark=(*pskb)->nfmark=nld->mark; + else + nlhdr.mark=(*pskb)->nfmark; + + if ( in && in->name ) { + strncpy((char *)&nlhdr.iface, in->name, IFNAMSIZ); + }else if ( out && out->name ){ + strncpy((char *)&nlhdr.iface, out->name, IFNAMSIZ); + } + + skb_put(outskb, len); + memcpy(outskb->data, &nlhdr, sizeof(nlhdr)); + memcpy((outskb->data)+sizeof(nlhdr), ip, len-sizeof(nlhdr)); + netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_ATOMIC); + }else{ + if (net_ratelimit()) + printk(KERN_WARNING "ipt_NETLINK: packet drop due to netlink failure\n"); + } + + if ( MASK(nld->flags, USE_DROP) ) + return NF_DROP; + + return IPT_CONTINUE; +} + +static int ipt_netlink_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hookmask) +{ + //struct ipt_nldata *nld = (struct ipt_nldata *)targinfo; + + return 1; +} + +static struct ipt_target ipt_netlink_reg = { + {NULL, NULL}, + "NETLINK", + ipt_netlink_target, + ipt_netlink_checkentry, + NULL, + THIS_MODULE +}; + +static int __init init(void) +{ + DEBUGP("ipt_NETLINK: init module\n"); + + if (ipt_register_target(&ipt_netlink_reg) != 0) { + return -EINVAL; + } + + if ( !(ipfwsk=netlink_kernel_create(NETLINK_FIREWALL, NULL)) ){ + return -EINVAL; + } + + return 0; +} + +static void __exit fini(void) +{ + DEBUGP("ipt_NETLINK: cleanup_module\n"); + ipt_unregister_target(&ipt_netlink_reg); + if(ipfwsk->socket) sock_release(ipfwsk->socket); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_NOTRACK.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_NOTRACK.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_NOTRACK.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_NOTRACK.c 2003-12-10 23:13:24.663326688 +0100 @@ -0,0 +1,79 @@ +/* This is a module which is used for setting up fake conntracks + * on packets so that they are not seen by the conntrack/NAT code. + */ +#include +#include + +#include +#include + +static unsigned int +target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, + void *userinfo) +{ + /* Previously seen (loopback)? Ignore. */ + if ((*pskb)->nfct != NULL) + return IPT_CONTINUE; + + /* Attach fake conntrack entry. + If there is a real ct entry correspondig to this packet, + it'll hang aroun till timing out. We don't deal with it + for performance reasons. JK */ + (*pskb)->nfct = &ip_conntrack_untracked.infos[IP_CT_NEW]; + nf_conntrack_get((*pskb)->nfct); + + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (targinfosize != 0) { + printk(KERN_WARNING "NOTRACK: targinfosize %u != 0\n", + targinfosize); + return 0; + } + + if (strcmp(tablename, "raw") != 0) { + printk(KERN_WARNING "NOTRACK: can only be called from \"raw\" table, not \"%s\"\n", tablename); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_notrack_reg = { + .name = "NOTRACK", + .target = target, + .checkentry = checkentry, + .destroy = NULL, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_notrack_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_notrack_reg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_DESCRIPTION("IPv4 NOTRACK target"); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_nth.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_nth.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_nth.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_nth.c 2003-12-10 23:13:37.748337464 +0100 @@ -0,0 +1,172 @@ +/* + This is a module which is used for match support for every Nth packet + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2001-07-18 Fabrice MARIE : initial implementation. + 2001-09-20 Richard Wagner (rwagner@cloudnet.com) + * added support for multiple counters + * added support for matching on individual packets + in the counter cycle + +*/ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* + * State information. + */ +struct state { + spinlock_t lock; + u_int16_t number; +}; + +static struct state states[IPT_NTH_NUM_COUNTERS]; + +static int +ipt_nth_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* Parameters from userspace */ + const struct ipt_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1); + return 0; + }; + + spin_lock(&states[counter].lock); + + /* Are we matching every nth packet?*/ + if (info->packet == 0xFF) + { + /* We're matching every nth packet and only every nth packet*/ + /* Do we match or invert match? */ + if (info->not == 0) + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto match; + } + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto dontmatch; + } + else + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto dontmatch; + } + if (states[counter].number >= info->every) + states[counter].number = 0; + else + ++states[counter].number; + goto match; + } + } + else + { + /* We're using the --packet, so there must be a rule for every value */ + if (states[counter].number == info->packet) + { + /* only increment the counter when a match happens */ + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto match; + } + else + goto dontmatch; + } + + dontmatch: + /* don't match */ + spin_unlock(&states[counter].lock); + return 0; + + match: + spin_unlock(&states[counter].lock); + return 1; +} + +static int +ipt_nth_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Parameters from userspace */ + const struct ipt_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IPT_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IPT_NTH_NUM_COUNTERS-1); + return 0; + }; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_nth_info))) { + printk("nth: matchsize %u != %u\n", matchsize, + IPT_ALIGN(sizeof(struct ipt_nth_info))); + return 0; + } + + states[counter].number = info->startat; + + return 1; +} + +static struct ipt_match ipt_nth_reg = { + {NULL, NULL}, + "nth", + ipt_nth_match, + ipt_nth_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + unsigned counter; + memset(&states, 0, sizeof(states)); + if (ipt_register_match(&ipt_nth_reg)) + return -EINVAL; + + for(counter = 0; counter < IPT_NTH_NUM_COUNTERS; counter++) + { + spin_lock_init(&(states[counter].lock)); + }; + + printk("ipt_nth match loaded\n"); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_nth_reg); + printk("ipt_nth match unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_osf.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_osf.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_osf.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_osf.c 2003-12-10 23:13:38.896162968 +0100 @@ -0,0 +1,699 @@ +/* + * ipt_osf.c + * + * Copyright (c) 2003 Evgeniy Polyakov + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * OS fingerprint matching module. + * It simply compares various parameters from SYN packet with + * some hardcoded ones. + * + * Original table was created by Michal Zalewski + * for his p0f. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +//#define OSF_DEBUG + +#ifdef OSF_DEBUG +#define log(x...) printk(KERN_INFO "ipt_osf: " x) +#define loga(x...) printk(x) +#else +#define log(x...) do {} while(0) +#define loga(x...) do {} while(0) +#endif + +#define FMATCH_WRONG 0 +#define FMATCH_OK 1 +#define FMATCH_OPT_WRONG 2 + +#define OPTDEL ',' +#define OSFPDEL ':' +#define MAXOPTSTRLEN 128 +#define OSFFLUSH "FLUSH" + +static rwlock_t osf_lock = RW_LOCK_UNLOCKED; +static struct list_head finger_list; + +static int match(const struct sk_buff *, const struct net_device *, const struct net_device *, + const void *, int, const void *, u_int16_t, int *); +static int checkentry(const char *, const struct ipt_ip *, void *, + unsigned int, unsigned int); + +static struct ipt_match osf_match = +{ + { NULL, NULL }, + "osf", + &match, + &checkentry, + NULL, + THIS_MODULE +}; + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + struct ipt_osf_info *info = (struct ipt_osf_info *)matchinfo; + struct iphdr *ip = skb->nh.iph; + struct tcphdr *tcp; + int fmatch = FMATCH_WRONG; + unsigned long totlen, optsize = 0, window; + unsigned char df, *optp = NULL, *_optp = NULL; + char check_WSS = 0; + struct list_head *ent; + struct osf_finger *f; + + if (!ip || !info) + return 0; + + tcp = (struct tcphdr *)((u_int32_t *)ip + ip->ihl); + + if (!tcp->syn) + return 0; + + totlen = ntohs(ip->tot_len); + df = ((ntohs(ip->frag_off) & IP_DF)?1:0); + window = ntohs(tcp->window); + + if (tcp->doff*4 > sizeof(struct tcphdr)) + { + _optp = optp = (char *)(tcp+1); + optsize = tcp->doff*4 - sizeof(struct tcphdr); + } + + + /* Actually we can create hash/table of all genres and search + * only in appropriate part, but here is initial variant, + * so will use slow path. + */ + read_lock(&osf_lock); + list_for_each(ent, &finger_list) + { + f = list_entry(ent, struct osf_finger, flist); + + if (strcmp(info->genre, f->genre)) + continue; + + optp = _optp; + + if ( ip->ttl == f->ttl && + totlen == f->ss && + df == f->df) + { + unsigned long foptsize; + int optnum; + unsigned short mss = 0; + + check_WSS = 0; + + switch (f->wss.wc) + { + case 0: check_WSS = 0; break; + case 'S': check_WSS = 1; break; + case 'T': check_WSS = 2; break; + case '%': check_WSS = 3; break; + default: log("Wrong fingerprint wss.wc=%d, %s - %s\n", + f->wss.wc, f->genre, f->details); + check_WSS = 4; + break; + } + if (check_WSS == 4) + continue; + + /* Check options */ + + foptsize = 0; + for (optnum=0; optnumopt_num; ++optnum) + foptsize += f->opt[optnum].length; + + + if (foptsize > MAX_IPOPTLEN || optsize > MAX_IPOPTLEN || optsize != foptsize) + continue; + + if (!optp) + { + fmatch = FMATCH_OK; + loga("\tYEP : matching without options.\n"); + break; + } + + + for (optnum=0; optnumopt_num; ++optnum) + { + if (f->opt[optnum].kind == (*optp)) + { + unsigned char len = f->opt[optnum].length; + unsigned char *optend = optp + len; + + fmatch = FMATCH_OK; + + if (*optp == OSFOPT_MSS) /* MSS */ + mss = ntohs(*(unsigned short *)(optp+2)); + + if (len != 1) + { + /* Skip kind and length fields*/ + optp += 2; + + if (f->opt[optnum].wc.wc != 0) + { + unsigned long tmp = 0; + + /* Hmmm... It looks a bit ugly. :) */ + memcpy(&tmp, &f->opt[optnum].wc.val, + (len > sizeof(unsigned long)? + sizeof(unsigned long):len)); + + tmp = ntohl(tmp); + if (tmp != f->opt[optnum].wc.val) + fmatch = FMATCH_OPT_WRONG; + } + } + + optp = optend; + } + else + fmatch = FMATCH_OPT_WRONG; + + if (fmatch != FMATCH_OK) + break; + } + + if (fmatch != FMATCH_OPT_WRONG) + { + fmatch = FMATCH_WRONG; + + switch (check_WSS) + { + case 0: + if (window == f->wss.val) + fmatch = FMATCH_OK; + break; + case 1: /* MSS */ + if (window == f->wss.val*mss) + fmatch = FMATCH_OK; + break; + case 2: /* MTU */ + if (window == f->wss.val*(mss+40)) + fmatch = FMATCH_OK; + break; + case 3: /* MOD */ + if (window % f->wss.val == 0) + fmatch = FMATCH_OK; + break; + } + } + + + if (fmatch == FMATCH_OK) + { + + log("genre %s[%25s]: ttl=%d, size=%lu, df=%d, " + "check_WSS=%d, win=%lu, optsize=%lu:\n", + f->genre, f->details, + ip->ttl, totlen, df, + check_WSS, window, optsize); + break; + } + } + } + read_unlock(&osf_lock); + + return (fmatch == FMATCH_OK)?1:0; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_osf_info))) + return 0; + if (ip->proto != IPPROTO_TCP) + return 0; + + return 1; +} + +static char * osf_strchr(char *ptr, char c) +{ + char *tmp; + + tmp = strchr(ptr, c); + + while (tmp && tmp+1 && isspace(*(tmp+1))) + tmp++; + + return tmp; +} + +static struct osf_finger * finger_alloc() +{ + struct osf_finger *f; + + f = kmalloc(sizeof(struct osf_finger), GFP_KERNEL); + if (f) + memset(f, 0, sizeof(struct osf_finger)); + + return f; +} + +static void finger_free(struct osf_finger *f) +{ + memset(f, 0, sizeof(struct osf_finger)); + kfree(f); +} + + +static void osf_parse_opt(struct osf_opt *opt, int *optnum, char *obuf, int olen) +{ + int i, op; + char *ptr, wc; + unsigned long val; + + ptr = &obuf[0]; + i = 0; + while (ptr != NULL && i < olen) + { + val = 0; + op = 0; + wc = 0; + switch (obuf[i]) + { + case 'N': + op = OSFOPT_NOP; + ptr = osf_strchr(&obuf[i], OPTDEL); + if (ptr) + { + *ptr = '\0'; + ptr++; + i += (int)(ptr-&obuf[i]); + + } + else + i++; + break; + case 'S': + op = OSFOPT_SACKP; + ptr = osf_strchr(&obuf[i], OPTDEL); + if (ptr) + { + *ptr = '\0'; + ptr++; + i += (int)(ptr-&obuf[i]); + + } + else + i++; + break; + case 'T': + op = OSFOPT_TS; + ptr = osf_strchr(&obuf[i], OPTDEL); + if (ptr) + { + *ptr = '\0'; + ptr++; + i += (int)(ptr-&obuf[i]); + + } + else + i++; + break; + case 'W': + op = OSFOPT_WSO; + ptr = osf_strchr(&obuf[i], OPTDEL); + if (ptr) + { + switch (obuf[i+1]) + { + case '%': wc = '%'; break; + case 'S': wc = 'S'; break; + case 'T': wc = 'T'; break; + default: wc = 0; break; + } + + *ptr = '\0'; + ptr++; + if (wc) + val = simple_strtoul(&obuf[i+2], NULL, 10); + else + val = simple_strtoul(&obuf[i+1], NULL, 10); + i += (int)(ptr-&obuf[i]); + + } + else + i++; + break; + case 'M': + op = OSFOPT_MSS; + ptr = osf_strchr(&obuf[i], OPTDEL); + if (ptr) + { + if (obuf[i+1] == '%') + wc = '%'; + *ptr = '\0'; + ptr++; + if (wc) + val = simple_strtoul(&obuf[i+2], NULL, 10); + else + val = simple_strtoul(&obuf[i+1], NULL, 10); + i += (int)(ptr-&obuf[i]); + + } + else + i++; + break; + case 'E': + op = OSFOPT_EOL; + ptr = osf_strchr(&obuf[i], OPTDEL); + if (ptr) + { + *ptr = '\0'; + ptr++; + i += (int)(ptr-&obuf[i]); + + } + else + i++; + break; + default: + ptr = osf_strchr(&obuf[i], OPTDEL); + if (ptr) + { + ptr++; + i += (int)(ptr-&obuf[i]); + + } + else + i++; + break; + } + + opt[*optnum].kind = IANA_opts[op].kind; + opt[*optnum].length = IANA_opts[op].length; + opt[*optnum].wc.wc = wc; + opt[*optnum].wc.val = val; + + log("opt %2d: kind=%2d, length=%2d, wc.wc=%d, wc.val=%5lu\n", + *optnum, opt[*optnum].kind, opt[*optnum].length, + opt[*optnum].wc.wc, opt[*optnum].wc.val); + + (*optnum)++; + } +} + +static int osf_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data) +{ + struct list_head *ent; + struct osf_finger *f = NULL; + int i; + + *eof = 1; + count = 0; + + read_lock_bh(&osf_lock); + list_for_each(ent, &finger_list) + { + f = list_entry(ent, struct osf_finger, flist); + + log("%s - %s: ttl=%d, wss=%c%lu, df=%d, size=%lu", + f->genre, f->details, f->ttl, (f->wss.wc)?f->wss.wc:' ', f->wss.val, f->df, f->ss); + + count += sprintf(buf+count, "%s - %s[%s] : %s", + f->genre, f->version, + f->subtype, f->details); + + if (f->opt_num) + { + loga(" OPT: "); + //count += sprintf(buf+count, " OPT: "); + for (i=0; iopt_num; ++i) + { + //count += sprintf(buf+count, "%d.%c%lu; ", + // f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val); + loga("%d.%c%lu; ", + f->opt[i].kind, (f->opt[i].wc.wc)?f->opt[i].wc.wc:' ', f->opt[i].wc.val); + } + } + loga("\n"); + count += sprintf(buf+count, "\n"); + } + read_unlock_bh(&osf_lock); + + return count; +} + +static int osf_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) +{ + int cnt; + unsigned long i; + char obuf[MAXOPTSTRLEN]; + struct osf_finger *finger; + struct list_head *ent, *n; + + char *pbeg, *pend; + + if (count == strlen(OSFFLUSH) && !strncmp(buffer, OSFFLUSH, strlen(OSFFLUSH))) + { + int i = 0; + write_lock_bh(&osf_lock); + list_for_each_safe(ent, n, &finger_list) + { + i++; + finger = list_entry(ent, struct osf_finger, flist); + list_del(&finger->flist); + finger_free(finger); + } + write_unlock_bh(&osf_lock); + + log("Flushed %d entries.\n", i); + + return count; + } + + + cnt = 0; + for (i=0; iwss.wc = 'S'; + if (pbeg[1] == '%') + finger->wss.val = simple_strtoul(pbeg+2, NULL, 10); + else if (pbeg[1] == '*') + finger->wss.val = 0; + else + finger->wss.val = simple_strtoul(pbeg+1, NULL, 10); + } + else if (pbeg[0] == 'T') + { + finger->wss.wc = 'T'; + if (pbeg[1] == '%') + finger->wss.val = simple_strtoul(pbeg+2, NULL, 10); + else if (pbeg[1] == '*') + finger->wss.val = 0; + else + finger->wss.val = simple_strtoul(pbeg+1, NULL, 10); + } + if (isdigit(pbeg[0])) + { + finger->wss.wc = 0; + finger->wss.val = simple_strtoul(pbeg, NULL, 10); + } + + pbeg = pend+1; + } + pend = osf_strchr(pbeg, OSFPDEL); + if (pend) + { + *pend = '\0'; + finger->ttl = simple_strtoul(pbeg, NULL, 10); + pbeg = pend+1; + } + pend = osf_strchr(pbeg, OSFPDEL); + if (pend) + { + *pend = '\0'; + finger->df = simple_strtoul(pbeg, NULL, 10); + pbeg = pend+1; + } + pend = osf_strchr(pbeg, OSFPDEL); + if (pend) + { + *pend = '\0'; + finger->ss = simple_strtoul(pbeg, NULL, 10); + pbeg = pend+1; + } + + pend = osf_strchr(pbeg, OSFPDEL); + if (pend) + { + *pend = '\0'; + cnt = snprintf(obuf, sizeof(obuf), "%s", pbeg); + pbeg = pend+1; + } + + pend = osf_strchr(pbeg, OSFPDEL); + if (pend) + { + *pend = '\0'; + if (pbeg[0] == '@' || pbeg[0] == '*') + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg+1); + else + cnt = snprintf(finger->genre, sizeof(finger->genre), "%s", pbeg); + pbeg = pend+1; + } + + pend = osf_strchr(pbeg, OSFPDEL); + if (pend) + { + *pend = '\0'; + cnt = snprintf(finger->version, sizeof(finger->version), "%s", pbeg); + pbeg = pend+1; + } + + pend = osf_strchr(pbeg, OSFPDEL); + if (pend) + { + *pend = '\0'; + cnt = snprintf(finger->subtype, sizeof(finger->subtype), "%s", pbeg); + pbeg = pend+1; + } + + cnt = snprintf(finger->details, + ((count - (pbeg - buffer)+1) > MAXDETLEN)?MAXDETLEN:(count - (pbeg - buffer)+1), + "%s", pbeg); + + log("%s - %s[%s] : %s\n", + finger->genre, finger->version, + finger->subtype, finger->details); + + osf_parse_opt(finger->opt, &finger->opt_num, obuf, sizeof(obuf)); + + + write_lock_bh(&osf_lock); + list_add(&finger->flist, &finger_list); + write_unlock_bh(&osf_lock); + + return count; +} + +static int __init osf_init(void) +{ + int err; + struct proc_dir_entry *p; + + log("Startng OS fingerprint matching module.\n"); + + INIT_LIST_HEAD(&finger_list); + + err = ipt_register_match(&osf_match); + if (err) + { + log("Failed to register OS fingerprint matching module.\n"); + return -ENXIO; + } + + p = create_proc_entry("sys/net/ipv4/osf", S_IFREG | 0644, NULL); + if (!p) + { + ipt_unregister_match(&osf_match); + return -ENXIO; + } + + p->write_proc = osf_proc_write; + p->read_proc = osf_proc_read; + + return 0; +} + +static void __exit osf_fini(void) +{ + struct list_head *ent, *n; + struct osf_finger *f; + + remove_proc_entry("sys/net/ipv4/osf", NULL); + ipt_unregister_match(&osf_match); + + list_for_each_safe(ent, n, &finger_list) + { + f = list_entry(ent, struct osf_finger, flist); + list_del(&f->flist); + finger_free(f); + } + + log("OS fingerprint matching module finished.\n"); +} + +module_init(osf_init); +module_exit(osf_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov "); +MODULE_DESCRIPTION("Passive OS fingerprint matching."); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_pool.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_pool.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_pool.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_pool.c 2003-12-10 23:13:39.982997744 +0100 @@ -0,0 +1,71 @@ +/* Kernel module to match an IP address pool. */ + +#include +#include +#include + +#include +#include +#include + +static inline int match_pool( + ip_pool_t index, + __u32 addr, + int inv +) { + if (ip_pool_match(index, ntohl(addr))) + inv = !inv; + return inv; +} + +static int match( + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop +) { + const struct ipt_pool_info *info = matchinfo; + const struct iphdr *iph = skb->nh.iph; + + if (info->src != IP_POOL_NONE && !match_pool(info->src, iph->saddr, + info->flags&IPT_POOL_INV_SRC)) + return 0; + + if (info->dst != IP_POOL_NONE && !match_pool(info->dst, iph->daddr, + info->flags&IPT_POOL_INV_DST)) + return 0; + + return 1; +} + +static int checkentry( + const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask +) { + if (matchsize != IPT_ALIGN(sizeof(struct ipt_pool_info))) + return 0; + return 1; +} + +static struct ipt_match pool_match += { { NULL, NULL }, "pool", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&pool_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&pool_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_POOL.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_POOL.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_POOL.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_POOL.c 2003-12-10 23:13:39.982997744 +0100 @@ -0,0 +1,116 @@ +/* ipt_POOL.c - netfilter target to manipulate IP pools + * + * This target can be used almost everywhere. It acts on some specified + * IP pool, adding or deleting some IP address in the pool. The address + * can be either the source (--addsrc, --delsrc), or destination (--add/deldst) + * of the packet under inspection. + * + * The target normally returns IPT_CONTINUE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/*** NOTE NOTE NOTE NOTE *** +** +** By sheer luck, I get away with using the "struct ipt_pool_info", as defined +** in , both as the match and target info. +** Here, in the target implementation, ipt_pool_info.src, if not IP_POOL_NONE, +** is modified for the source IP address of the packet under inspection. +** The same way, the ipt_pool_info.dst pool is modified for the destination. +** +** The address is added to the pool normally. However, if IPT_POOL_DEL_dir +** flag is set in ipt_pool_info.flags, the address is deleted from the pool. +** +** If a modification was done to the pool, we possibly return ACCEPT or DROP, +** if the right IPT_POOL_MOD_dir_ACCEPT or _MOD_dir_DROP flags are set. +** The IPT_POOL_INV_MOD_dir flag inverts the sense of the check (i.e. the +** ACCEPT and DROP flags are evaluated when the pool was not modified.) +*/ + +static int +do_check(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const struct ipt_pool_info *ipi = targinfo; + + if (targinfosize != IPT_ALIGN(sizeof(*ipi))) { + DEBUGP("POOL_check: size %u.\n", targinfosize); + return 0; + } + DEBUGP("ipt_POOL:do_check(%d,%d,%d)\n",ipi->src,ipi->dst,ipi->flags); + return 1; +} + +static unsigned int +do_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_pool_info *ipi = targinfo; + int modified; + unsigned int verdict = IPT_CONTINUE; + + if (ipi->src != IP_POOL_NONE) { + modified = ip_pool_mod(ipi->src, ntohl((*pskb)->nh.iph->saddr), + ipi->flags & IPT_POOL_DEL_SRC); + if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_SRC)) { + if (ipi->flags & IPT_POOL_MOD_SRC_ACCEPT) + verdict = NF_ACCEPT; + else if (ipi->flags & IPT_POOL_MOD_SRC_DROP) + verdict = NF_DROP; + } + } + if (verdict == IPT_CONTINUE && ipi->dst != IP_POOL_NONE) { + modified = ip_pool_mod(ipi->dst, ntohl((*pskb)->nh.iph->daddr), + ipi->flags & IPT_POOL_DEL_DST); + if (!!modified ^ !!(ipi->flags & IPT_POOL_INV_MOD_DST)) { + if (ipi->flags & IPT_POOL_MOD_DST_ACCEPT) + verdict = NF_ACCEPT; + else if (ipi->flags & IPT_POOL_MOD_DST_DROP) + verdict = NF_DROP; + } + } + return verdict; +} + +static struct ipt_target pool_reg += { { NULL, NULL }, "POOL", do_target, do_check, NULL, THIS_MODULE }; + +static int __init init(void) +{ + DEBUGP("init ipt_POOL\n"); + return ipt_register_target(&pool_reg); +} + +static void __exit fini(void) +{ + DEBUGP("fini ipt_POOL\n"); + ipt_unregister_target(&pool_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_psd.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_psd.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_psd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_psd.c 2003-12-10 23:13:41.104827200 +0100 @@ -0,0 +1,361 @@ +/* + This is a module which is used for PSD (portscan detection) + Derived from scanlogd v2.1 written by Solar Designer + and LOG target module. + + Copyright (C) 2000,2001 astaro AG + + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2000-05-04 Markus Hennig : initial + 2000-08-18 Dennis Koslowski : first release + 2000-12-01 Dennis Koslowski : UDP scans detection added + 2001-01-02 Dennis Koslowski : output modified + 2001-02-04 Jan Rekorajski : converted from target to match +*/ + +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dennis Koslowski "); + +#define HF_DADDR_CHANGING 0x01 +#define HF_SPORT_CHANGING 0x02 +#define HF_TOS_CHANGING 0x04 +#define HF_TTL_CHANGING 0x08 + +/* + * Information we keep per each target port + */ +struct port { + u_int16_t number; /* port number */ + u_int8_t proto; /* protocol number */ + u_int8_t and_flags; /* tcp ANDed flags */ + u_int8_t or_flags; /* tcp ORed flags */ +}; + +/* + * Information we keep per each source address. + */ +struct host { + struct host *next; /* Next entry with the same hash */ + clock_t timestamp; /* Last update time */ + struct in_addr src_addr; /* Source address */ + struct in_addr dest_addr; /* Destination address */ + unsigned short src_port; /* Source port */ + int count; /* Number of ports in the list */ + int weight; /* Total weight of ports in the list */ + struct port ports[SCAN_MAX_COUNT - 1]; /* List of ports */ + unsigned char tos; /* TOS */ + unsigned char ttl; /* TTL */ + unsigned char flags; /* HF_ flags bitmask */ +}; + +/* + * State information. + */ +static struct { + spinlock_t lock; + struct host list[LIST_SIZE]; /* List of source addresses */ + struct host *hash[HASH_SIZE]; /* Hash: pointers into the list */ + int index; /* Oldest entry to be replaced */ +} state; + +/* + * Convert an IP address into a hash table index. + */ +static inline int hashfunc(struct in_addr addr) +{ + unsigned int value; + int hash; + + value = addr.s_addr; + hash = 0; + do { + hash ^= value; + } while ((value >>= HASH_LOG)); + + return hash & (HASH_SIZE - 1); +} + +static int +ipt_psd_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + struct iphdr *ip_hdr; + struct tcphdr *tcp_hdr; + struct in_addr addr; + u_int16_t src_port,dest_port; + u_int8_t tcp_flags, proto; + clock_t now; + struct host *curr, *last, **head; + int hash, index, count; + + /* Parameters from userspace */ + const struct ipt_psd_info *psdinfo = matchinfo; + + /* IP header */ + ip_hdr = pskb->nh.iph; + + /* Sanity check */ + if (ntohs(ip_hdr->frag_off) & IP_OFFSET) { + DEBUGP("PSD: sanity check failed\n"); + return 0; + } + + /* TCP or UDP ? */ + proto = ip_hdr->protocol; + + if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) { + DEBUGP("PSD: protocol not supported\n"); + return 0; + } + + /* Get the source address, source & destination ports, and TCP flags */ + + addr.s_addr = ip_hdr->saddr; + + tcp_hdr = (struct tcphdr*)((u_int32_t *)ip_hdr + ip_hdr->ihl); + + /* Yep, it´s dirty */ + src_port = tcp_hdr->source; + dest_port = tcp_hdr->dest; + + if (proto == IPPROTO_TCP) { + tcp_flags = *((u_int8_t*)tcp_hdr + 13); + } + else { + tcp_flags = 0x00; + } + + /* We're using IP address 0.0.0.0 for a special purpose here, so don't let + * them spoof us. [DHCP needs this feature - HW] */ + if (!addr.s_addr) { + DEBUGP("PSD: spoofed source address (0.0.0.0)\n"); + return 0; + } + + /* Use jiffies here not to depend on someone setting the time while we're + * running; we need to be careful with possible return value overflows. */ + now = jiffies; + + spin_lock(&state.lock); + + /* Do we know this source address already? */ + count = 0; + last = NULL; + if ((curr = *(head = &state.hash[hash = hashfunc(addr)]))) + do { + if (curr->src_addr.s_addr == addr.s_addr) break; + count++; + if (curr->next) last = curr; + } while ((curr = curr->next)); + + if (curr) { + + /* We know this address, and the entry isn't too old. Update it. */ + if (now - curr->timestamp <= (psdinfo->delay_threshold*HZ)/100 && + time_after_eq(now, curr->timestamp)) { + + /* Just update the appropriate list entry if we've seen this port already */ + for (index = 0; index < curr->count; index++) { + if (curr->ports[index].number == dest_port) { + curr->ports[index].proto = proto; + curr->ports[index].and_flags &= tcp_flags; + curr->ports[index].or_flags |= tcp_flags; + goto out_no_match; + } + } + + /* TCP/ACK and/or TCP/RST to a new port? This could be an outgoing connection. */ + if (proto == IPPROTO_TCP && (tcp_hdr->ack || tcp_hdr->rst)) + goto out_no_match; + + /* Packet to a new port, and not TCP/ACK: update the timestamp */ + curr->timestamp = now; + + /* Logged this scan already? Then drop the packet. */ + if (curr->weight >= psdinfo->weight_threshold) + goto out_match; + + /* Specify if destination address, source port, TOS or TTL are not fixed */ + if (curr->dest_addr.s_addr != ip_hdr->daddr) + curr->flags |= HF_DADDR_CHANGING; + if (curr->src_port != src_port) + curr->flags |= HF_SPORT_CHANGING; + if (curr->tos != ip_hdr->tos) + curr->flags |= HF_TOS_CHANGING; + if (curr->ttl != ip_hdr->ttl) + curr->flags |= HF_TTL_CHANGING; + + /* Update the total weight */ + curr->weight += (ntohs(dest_port) < 1024) ? + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; + + /* Got enough destination ports to decide that this is a scan? */ + /* Then log it and drop the packet. */ + if (curr->weight >= psdinfo->weight_threshold) + goto out_match; + + /* Remember the new port */ + if (curr->count < SCAN_MAX_COUNT) { + curr->ports[curr->count].number = dest_port; + curr->ports[curr->count].proto = proto; + curr->ports[curr->count].and_flags = tcp_flags; + curr->ports[curr->count].or_flags = tcp_flags; + curr->count++; + } + + goto out_no_match; + } + + /* We know this address, but the entry is outdated. Mark it unused, and + * remove from the hash table. We'll allocate a new entry instead since + * this one might get re-used too soon. */ + curr->src_addr.s_addr = 0; + if (last) + last->next = last->next->next; + else if (*head) + *head = (*head)->next; + last = NULL; + } + + /* We don't need an ACK from a new source address */ + if (proto == IPPROTO_TCP && tcp_hdr->ack) + goto out_no_match; + + /* Got too many source addresses with the same hash value? Then remove the + * oldest one from the hash table, so that they can't take too much of our + * CPU time even with carefully chosen spoofed IP addresses. */ + if (count >= HASH_MAX && last) last->next = NULL; + + /* We're going to re-use the oldest list entry, so remove it from the hash + * table first (if it is really already in use, and isn't removed from the + * hash table already because of the HASH_MAX check above). */ + + /* First, find it */ + if (state.list[state.index].src_addr.s_addr) + head = &state.hash[hashfunc(state.list[state.index].src_addr)]; + else + head = &last; + last = NULL; + if ((curr = *head)) + do { + if (curr == &state.list[state.index]) break; + last = curr; + } while ((curr = curr->next)); + + /* Then, remove it */ + if (curr) { + if (last) + last->next = last->next->next; + else if (*head) + *head = (*head)->next; + } + + /* Get our list entry */ + curr = &state.list[state.index++]; + if (state.index >= LIST_SIZE) state.index = 0; + + /* Link it into the hash table */ + head = &state.hash[hash]; + curr->next = *head; + *head = curr; + + /* And fill in the fields */ + curr->timestamp = now; + curr->src_addr = addr; + curr->dest_addr.s_addr = ip_hdr->daddr; + curr->src_port = src_port; + curr->count = 1; + curr->weight = (ntohs(dest_port) < 1024) ? + psdinfo->lo_ports_weight : psdinfo->hi_ports_weight; + curr->ports[0].number = dest_port; + curr->ports[0].proto = proto; + curr->ports[0].and_flags = tcp_flags; + curr->ports[0].or_flags = tcp_flags; + curr->tos = ip_hdr->tos; + curr->ttl = ip_hdr->ttl; + +out_no_match: + spin_unlock(&state.lock); + return 0; + +out_match: + spin_unlock(&state.lock); + return 1; +} + +static int ipt_psd_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ +/* const struct ipt_psd_info *psdinfo = targinfo;*/ + + /* we accept TCP only */ +/* if (e->ip.proto != IPPROTO_TCP) { */ +/* DEBUGP("PSD: specified protocol may be TCP only\n"); */ +/* return 0; */ +/* } */ + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_psd_info))) { + DEBUGP("PSD: matchsize %u != %u\n", + matchsize, + IPT_ALIGN(sizeof(struct ipt_psd_info))); + return 0; + } + + return 1; +} + +static struct ipt_match ipt_psd_reg = { + {NULL, NULL}, + "psd", + ipt_psd_match, + ipt_psd_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_match(&ipt_psd_reg)) + return -EINVAL; + + memset(&state, 0, sizeof(state)); + + spin_lock_init(&(state.lock)); + + printk("netfilter PSD loaded - (c) astaro AG\n"); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_psd_reg); + printk("netfilter PSD unloaded - (c) astaro AG\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_quota.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_quota.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_quota.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_quota.c 2003-12-10 23:13:42.204660000 +0100 @@ -0,0 +1,81 @@ +/* + * netfilter module to enforce network quotas + * + * Sam Johnston + */ +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); + +static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED; + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + + struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo; + + spin_lock_bh("a_lock); + + if (q->quota >= datalen) { + /* we can afford this one */ + q->quota -= datalen; + spin_unlock_bh("a_lock); + +#ifdef DEBUG_IPT_QUOTA + printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen); +#endif + return 1; + } + + /* so we do not allow even small packets from now on */ + q->quota = 0; + +#ifdef DEBUG_IPT_QUOTA + printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen); +#endif + + spin_unlock_bh("a_lock); + return 0; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + /* TODO: spinlocks? sanity checks? */ + if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info))) + return 0; + + return 1; +} + +static struct ipt_match quota_match + = { {NULL, NULL}, "quota", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init +init(void) +{ + return ipt_register_match("a_match); +} + +static void __exit +fini(void) +{ + ipt_unregister_match("a_match); +} + +module_init(init); +module_exit(fini); + diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_random.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_random.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_random.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_random.c 2003-12-10 23:13:44.404325600 +0100 @@ -0,0 +1,96 @@ +/* + This is a module which is used for a "random" match support. + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2001-10-14 Fabrice MARIE : initial implementation. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static int +ipt_rand_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* Parameters from userspace */ + const struct ipt_rand_info *info = matchinfo; + u_int8_t random_number; + + /* get 1 random number from the kernel random number generation routine */ + get_random_bytes((void *)(&random_number), 1); + + /* Do we match ? */ + if (random_number <= info->average) + return 1; + else + return 0; +} + +static int +ipt_rand_checkentry(const char *tablename, + const struct ipt_ip *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Parameters from userspace */ + const struct ipt_rand_info *info = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_rand_info))) { + printk("ipt_random: matchsize %u != %u\n", matchsize, + IPT_ALIGN(sizeof(struct ipt_rand_info))); + return 0; + } + + /* must be 1 <= average % <= 99 */ + /* 1 x 2.55 = 2 */ + /* 99 x 2.55 = 252 */ + if ((info->average < 2) || (info->average > 252)) { + printk("ipt_random: invalid average %u\n", info->average); + return 0; + } + + return 1; +} + +static struct ipt_match ipt_rand_reg = { + {NULL, NULL}, + "random", + ipt_rand_match, + ipt_rand_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_match(&ipt_rand_reg)) + return -EINVAL; + + printk("ipt_random match loaded\n"); + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_match(&ipt_rand_reg); + printk("ipt_random match unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_realm.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_realm.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_realm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_realm.c 2003-12-10 23:13:45.528154752 +0100 @@ -0,0 +1,68 @@ +/* Kernel module to match realm from routing. */ +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Sampsa Ranta "); +MODULE_LICENSE("GPL"); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_realm_info *info = matchinfo; + struct dst_entry *dst = skb->dst; + u32 id; + + if(dst == NULL) + return 0; + id = dst->tclassid; + + return (info->id == (id & info->mask)) ^ info->invert; +} + +static int check(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (hook_mask + & ~((1 << NF_IP_POST_ROUTING) | (1 << NF_IP_FORWARD) | + (1 << NF_IP_LOCAL_OUT)| (1 << NF_IP_LOCAL_IN))) { + printk("ipt_realm: only valid for POST_ROUTING, LOCAL_OUT, " + "LOCAL_IN or FORWARD.\n"); + return 0; + } + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_realm_info))) + return 0; + + return 1; +} + +static struct ipt_match realm_match += { { NULL, NULL }, "realm", &match, &check, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&realm_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&realm_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_REJECT.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_REJECT.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_REJECT.c 2003-11-26 21:45:22.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_REJECT.c 2003-12-10 23:14:20.643816360 +0100 @@ -2,6 +2,7 @@ * This is a module which is used for rejecting packets. * Added support for customized reject packets (Jozsef Kadlecsik). * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812] + * Added support for fake source IP in icmp-unreach (Fabrice MARIE & Guillaume MORIN). */ #include #include @@ -204,13 +205,13 @@ kfree_skb(nskb); } -static void send_unreach(struct sk_buff *skb_in, int code) +static void send_unreach(struct sk_buff *skb_in, int code, u_int8_t fake_source_address) { struct iphdr *iph; struct udphdr *udph; struct icmphdr *icmph; struct sk_buff *nskb; - u32 saddr; + u32 saddr,packet_daddr; u8 tos; int hh_len, length; struct rtable *rt = (struct rtable*)skb_in->dst; @@ -274,7 +275,7 @@ return; } - saddr = iph->daddr; + packet_daddr = saddr = iph->daddr; if (!(rt->rt_flags & RTCF_LOCAL)) saddr = 0; @@ -322,7 +323,16 @@ iph->ttl = MAXTTL; ip_select_ident(iph, &rt->u.dst, NULL); iph->protocol=IPPROTO_ICMP; - iph->saddr=rt->rt_src; + + /* fake source IP if we have to + if fake_source_address == 1, we fake the source IP + from the packet destination address dynamically. + */ + if (fake_source_address == 1) + iph->saddr = packet_daddr; + else + iph->saddr=rt->rt_src; + iph->daddr=rt->rt_dst; iph->check=0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); @@ -370,25 +380,25 @@ must return an absolute verdict. --RR */ switch (reject->with) { case IPT_ICMP_NET_UNREACHABLE: - send_unreach(*pskb, ICMP_NET_UNREACH); + send_unreach(*pskb, ICMP_NET_UNREACH, reject->fake_source_address); break; case IPT_ICMP_HOST_UNREACHABLE: - send_unreach(*pskb, ICMP_HOST_UNREACH); + send_unreach(*pskb, ICMP_HOST_UNREACH, reject->fake_source_address); break; case IPT_ICMP_PROT_UNREACHABLE: - send_unreach(*pskb, ICMP_PROT_UNREACH); + send_unreach(*pskb, ICMP_PROT_UNREACH, reject->fake_source_address); break; case IPT_ICMP_PORT_UNREACHABLE: - send_unreach(*pskb, ICMP_PORT_UNREACH); + send_unreach(*pskb, ICMP_PORT_UNREACH, reject->fake_source_address); break; case IPT_ICMP_NET_PROHIBITED: - send_unreach(*pskb, ICMP_NET_ANO); + send_unreach(*pskb, ICMP_NET_ANO, reject->fake_source_address); break; case IPT_ICMP_HOST_PROHIBITED: - send_unreach(*pskb, ICMP_HOST_ANO); + send_unreach(*pskb, ICMP_HOST_ANO, reject->fake_source_address); break; case IPT_ICMP_ADMIN_PROHIBITED: - send_unreach(*pskb, ICMP_PKT_FILTERED); + send_unreach(*pskb, ICMP_PKT_FILTERED, reject->fake_source_address); break; case IPT_TCP_RESET: send_reset(*pskb, hooknum); @@ -435,6 +445,11 @@ DEBUGP("REJECT: TCP_RESET invalid for non-tcp\n"); return 0; } + /* cannot fake source address */ + if (rejinfo->fake_source_address != 0) { + DEBUGP("REJECT: fake-source-address illegal for TCP-RESET\n"); + return 0; + } } return 1; diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_ROUTE.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ROUTE.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_ROUTE.c 2003-12-10 23:14:07.502814096 +0100 @@ -0,0 +1,369 @@ +/* + * This implements the ROUTE target, which enables you to setup unusual + * routes not supported by the standard kernel routing table. + * + * Copyright (C) 2002 Cedric de Launois + * + * v 1.8 2003/07/25 + * + * This software is distributed under GNU GPL v2, 1991 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + + +/* Try to route the packet according to the routing keys specified in + * route_info. Keys are : + * - ifindex : + * 0 if no oif preferred, + * otherwise set to the index of the desired oif + * - route_info->gw : + * 0 if no gateway specified, + * otherwise set to the next host to which the pkt must be routed + * If success, skb->dev is the output device to which the packet must + * be sent and skb->dst is not NULL + * + * RETURN: -1 if an error occured + * 1 if the packet was succesfully routed to the + * destination desired + * 0 if the kernel routing table could not route the packet + * according to the keys specified + */ +static int route(struct sk_buff *skb, + unsigned int ifindex, + const struct ipt_route_target_info *route_info) +{ + int err; + struct rtable *rt; + struct iphdr *iph = skb->nh.iph; + struct rt_key key = { + dst:iph->daddr, + src:0, + oif:ifindex, + tos:RT_TOS(iph->tos) + }; + + /* The destination address may be overloaded by the target */ + if (route_info->gw) + key.dst = route_info->gw; + + /* Trying to route the packet using the standard routing table. */ + if ((err = ip_route_output_key(&rt, &key))) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err); + return -1; + } + + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = NULL; + + /* Success if no oif specified or if the oif correspond to the + * one desired */ + if (!ifindex || rt->u.dst.dev->ifindex == ifindex) { + skb->dst = &rt->u.dst; + skb->dev = skb->dst->dev; + return 1; + } + + /* The interface selected by the routing table is not the one + * specified by the user. This may happen because the dst address + * is one of our own addresses. + */ + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n", + NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex); + + return 0; +} + + +/* Stolen from ip_finish_output2 + * PRE : skb->dev is set to the device we are leaving by + * skb->dst is not NULL + * POST: the packet is sent with the link layer header pushed + * the packet is destroyed + */ +static void ip_direct_send(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; + + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + hh->hh_output(skb); + } else if (dst->neighbour) + dst->neighbour->output(skb); + else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n"); + kfree_skb(skb); + } +} + + +/* PRE : skb->dev is set to the device we are leaving by + * POST: - the packet is directly sent to the skb->dev device, without + * pushing the link layer header. + * - the packet is destroyed + */ +static inline int dev_direct_send(struct sk_buff *skb) +{ + return dev_queue_xmit(skb); +} + + +static unsigned int route_oif(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + unsigned int ifindex = 0; + struct net_device *dev_out = NULL; + + /* The user set the interface name to use. + * Getting the current interface index. + */ + if ((dev_out = dev_get_by_name(route_info->oif))) { + ifindex = dev_out->ifindex; + } else { + /* Unknown interface name : packet dropped */ + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif); + return NF_DROP; + } + + /* Trying the standard way of routing packets */ + switch (route(skb, ifindex, route_info)) { + case 1: + dev_put(dev_out); + if (route_info->flags & IPT_ROUTE_CONTINUE) + return IPT_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + + case 0: + /* Failed to send to oif. Trying the hard way */ + if (route_info->flags & IPT_ROUTE_CONTINUE) + return NF_DROP; + + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: forcing the use of %i\n", + ifindex); + + /* We have to force the use of an interface. + * This interface must be a tunnel interface since + * otherwise we can't guess the hw address for + * the packet. For a tunnel interface, no hw address + * is needed. + */ + if ((dev_out->type != ARPHRD_TUNNEL) + && (dev_out->type != ARPHRD_IPGRE)) { + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: can't guess the hw addr !\n"); + dev_put(dev_out); + return NF_DROP; + } + + /* Send the packet. This will also free skb + * Do not go through the POST_ROUTING hook because + * skb->dst is not set and because it will probably + * get confused by the destination IP address. + */ + skb->dev = dev_out; + dev_direct_send(skb); + dev_put(dev_out); + return NF_STOLEN; + + default: + /* Unexpected error */ + dev_put(dev_out); + return NF_DROP; + } +} + + +static unsigned int route_iif(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + struct net_device *dev_out = NULL; + unsigned int ifindex = 0; + + /* Getting the current interface index. */ + if ((dev_out = dev_get_by_name(route_info->iif))) + ifindex = dev_out->ifindex; + else { + /* Unknown interface name : packet dropped */ + if (net_ratelimit()) + DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->oif); + return NF_DROP; + } + + skb->dev = dev_out; + dst_release(skb->dst); + skb->dst = NULL; + + netif_rx(skb); + + return NF_STOLEN; +} + + +static unsigned int route_gw(const struct ipt_route_target_info *route_info, + struct sk_buff *skb) +{ + if (route(skb, 0, route_info)!=1) + return NF_DROP; + + if (route_info->flags & IPT_ROUTE_CONTINUE) + return IPT_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; +} + + +static unsigned int ipt_route_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ipt_route_target_info *route_info = targinfo; + struct sk_buff *skb = *pskb; + + /* If we are at PREROUTING or INPUT hook + * the TTL isn't decreased by the IP stack + */ + if (hooknum == NF_IP_PRE_ROUTING || + hooknum == NF_IP_LOCAL_IN) { + + struct iphdr *iph = skb->nh.iph; + + if (iph->ttl <= 1) { + struct rtable *rt; + + if (ip_route_output(&rt, iph->saddr, iph->daddr, + RT_TOS(iph->tos) | RTO_CONN, + 0)) { + return NF_DROP; + } + + if (skb->dev == rt->u.dst.dev) { + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = &rt->u.dst; + + /* this will traverse normal stack, and + * thus call conntrack on the icmp packet */ + icmp_send(skb, ICMP_TIME_EXCEEDED, + ICMP_EXC_TTL, 0); + } + + return NF_DROP; + } + + ip_decrease_ttl(iph); + } + + /* Tell conntrack to forget this packet since it may get confused + * when a packet is leaving with dst address == our address. + * Good idea ? Dunno. Need advice. + */ + if (!(route_info->flags & IPT_ROUTE_CONTINUE)) { + nf_conntrack_put(skb->nfct); + skb->nfct = NULL; + skb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif + } + + if (route_info->oif[0]) + return route_oif(route_info, *pskb); + + if (route_info->iif[0]) + return route_iif(route_info, *pskb); + + if (route_info->gw) + return route_gw(route_info, *pskb); + + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n"); + + return IPT_CONTINUE; +} + + +static int ipt_route_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (strcmp(tablename, "mangle") != 0) { + printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n", + tablename); + return 0; + } + + if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING) + | (1 << NF_IP_LOCAL_IN) + | (1 << NF_IP_FORWARD) + | (1 << NF_IP_LOCAL_OUT) + | (1 << NF_IP_POST_ROUTING))) { + printk("ipt_ROUTE: bad hook\n"); + return 0; + } + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) { + printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_route_target_info))); + return 0; + } + + return 1; +} + + +static struct ipt_target ipt_route_reg += { { NULL, NULL }, "ROUTE", ipt_route_target, ipt_route_checkentry, NULL, + THIS_MODULE }; + + +static int __init init(void) +{ + if (ipt_register_target(&ipt_route_reg)) + return -EINVAL; + + return 0; +} + + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_route_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_rpc.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_rpc.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_rpc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_rpc.c 2003-12-10 23:14:10.155410840 +0100 @@ -0,0 +1,428 @@ +/* RPC extension for IP connection matching, Version 2.2 + * (C) 2000 by Marcelo Barbosa Lima + * - original rpc tracking module + * - "recent" connection handling for kernel 2.3+ netfilter + * + * (C) 2001 by Rusty Russell + * - upgraded conntrack modules to oldnat api - kernel 2.4.0+ + * + * (C) 2002,2003 by Ian (Larry) Latter + * - upgraded conntrack modules to newnat api - kernel 2.4.20+ + * - extended matching to support filtering on procedures + * + * ipt_rpc.c,v 2.2 2003/01/12 18:30:00 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + ** + * Module load syntax: + * insmod ipt_rpc.o ports=port1,port2,...port + * + * Please give the ports of all RPC servers you wish to connect to. + * If you don't specify ports, the default will be port 111. + ** + * Note to all: + * + * RPCs should not be exposed to the internet - ask the Pentagon; + * + * "The unidentified crackers pleaded guilty in July to charges + * of juvenile delinquency stemming from a string of Pentagon + * network intrusions in February. + * + * The youths, going by the names TooShort and Makaveli, used + * a common server security hole to break in, according to + * Dane Jasper, owner of the California Internet service + * provider, Sonic. They used the hole, known as the 'statd' + * exploit, to attempt more than 800 break-ins, Jasper said." + * + * From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998 + * URL: http://www.wired.com/news/politics/0,1283,16098,00.html + ** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_n_c = 0; + +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +MODULE_PARM_DESC(ports, "port numbers (TCP/UDP) of RPC portmapper servers"); +#endif + +MODULE_AUTHOR("Marcelo Barbosa Lima "); +MODULE_DESCRIPTION("RPC connection matching module"); +MODULE_LICENSE("GPL"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "ipt_rpc: " \ + format, ## args) +#else +#define DEBUGP(format, args...) +#endif + +EXPORT_NO_SYMBOLS; + +/* vars from ip_conntrack_rpc_tcp */ +extern struct list_head request_p_list_tcp; +extern struct module *ip_conntrack_rpc_tcp; + +/* vars from ip_conntrack_rpc_udp */ +extern struct list_head request_p_list_udp; +extern struct module *ip_conntrack_rpc_udp; + +DECLARE_RWLOCK_EXTERN(ipct_rpc_tcp_lock); +DECLARE_RWLOCK_EXTERN(ipct_rpc_udp_lock); + +#define ASSERT_READ_LOCK(x) \ +do { \ + if (x == &request_p_list_udp) \ + MUST_BE_READ_LOCKED(&ipct_rpc_udp_lock); \ + else if (x == &request_p_list_tcp) \ + MUST_BE_READ_LOCKED(&ipct_rpc_tcp_lock); \ +} while (0) + +#define ASSERT_WRITE_LOCK(x) \ +do { \ + if (x == &request_p_list_udp) \ + MUST_BE_WRITE_LOCKED(&ipct_rpc_udp_lock); \ + else if (x == &request_p_list_tcp) \ + MUST_BE_WRITE_LOCKED(&ipct_rpc_tcp_lock); \ +} while (0) + +#include + +const int IPT_RPC_CHAR_LEN = 11; + + +static int k_atoi(char *string) +{ + unsigned int result = 0; + int maxoctet = IPT_RPC_CHAR_LEN; + + for ( ; *string != 0 && maxoctet != 0; maxoctet--, string++) { + if (*string < 0) + return(0); + if (*string == 0) + break; + if (*string < 48 || *string > 57) { + return(0); + } + result = result * 10 + ( *string - 48 ); + } + return(result); +} + + +static int match_rpcs(char *c_procs, int i_procs, int proc) +{ + int proc_ctr; + char *proc_ptr; + unsigned int proc_num; + + DEBUGP("entered match_rpcs [%i] [%i] ..\n", i_procs, proc); + + if (i_procs == -1) + return 1; + + for (proc_ctr=0; proc_ctr <= i_procs; proc_ctr++) { + + proc_ptr = c_procs; + proc_ptr += proc_ctr * IPT_RPC_CHAR_LEN; + proc_num = k_atoi(proc_ptr); + + if (proc_num == proc) + return 1; + } + + return 0; +} + + +static int check_rpc_packet(const u_int32_t *data, const void *matchinfo, + int *hotdrop, int dir, struct ip_conntrack *ct, + int offset, struct list_head request_p_list) +{ + const struct ipt_rpc_info *rpcinfo = matchinfo; + struct request_p *req_p; + u_int32_t xid; + + + /* Get XID */ + xid = *data; + + /* This does sanity checking on RPC payloads, + * and permits only the RPC "get port" (3) + * in authorised procedures in client + * communications with the portmapper. + */ + + data += 5; + + /* Get RPC requestor */ + if (IXDR_GET_INT32(data) != 3) { + DEBUGP("RPC packet contains an invalid (non \"get\") requestor. [skip]\n"); + if(rpcinfo->strict == 1) + *hotdrop = 1; + return 0; + } + DEBUGP("RPC packet contains a \"get\" requestor. [cont]\n"); + + data++; + + /* Jump Credentials and Verfifier */ + data = data + IXDR_GET_INT32(data) + 2; + data = data + IXDR_GET_INT32(data) + 2; + + /* Get RPC procedure */ + if (match_rpcs((char *)&rpcinfo->c_procs, + rpcinfo->i_procs, IXDR_GET_INT32(data)) == 0) { + DEBUGP("RPC packet contains illegal procedure request [%u]. [drop]\n", + (unsigned int)IXDR_GET_INT32(data)); + + /* If the RPC conntrack half entry already exists .. */ + + switch (ct->tuplehash[0].tuple.dst.protonum) { + case IPPROTO_UDP: + WRITE_LOCK(&ipct_rpc_udp_lock); + case IPPROTO_TCP: + WRITE_LOCK(&ipct_rpc_tcp_lock); + } + req_p = LIST_FIND(&request_p_list, request_p_cmp, + struct request_p *, xid, + ct->tuplehash[dir].tuple.src.ip, + ct->tuplehash[dir].tuple.src.u.all); + + if (req_p) { + DEBUGP("found req_p for xid=%u proto=%u %u.%u.%u.%u:%u\n", + xid, ct->tuplehash[dir].tuple.dst.protonum, + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + ntohs(ct->tuplehash[dir].tuple.src.u.all)); + + /* .. remove it */ + if (del_timer(&req_p->timeout)) + req_p->timeout.expires = 0; + + LIST_DELETE(&request_p_list, req_p); + DEBUGP("RPC req_p removed. [done]\n"); + + } else { + DEBUGP("no req_p found for xid=%u proto=%u %u.%u.%u.%u:%u\n", + xid, ct->tuplehash[dir].tuple.dst.protonum, + NIPQUAD(ct->tuplehash[dir].tuple.src.ip), + ntohs(ct->tuplehash[dir].tuple.src.u.all)); + + } + switch (ct->tuplehash[0].tuple.dst.protonum) { + case IPPROTO_UDP: + WRITE_UNLOCK(&ipct_rpc_udp_lock); + case IPPROTO_TCP: + WRITE_UNLOCK(&ipct_rpc_tcp_lock); + } + + if(rpcinfo->strict == 1) + *hotdrop = 1; + return 0; + } + + DEBUGP("RPC packet contains authorised procedure request [%u]. [match]\n", + (unsigned int)IXDR_GET_INT32(data)); + return (1 && (!offset)); +} + + +static int match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, + int offset, const void *hdr, u_int16_t datalen, int *hotdrop) +{ + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + const u_int32_t *data; + enum ip_conntrack_dir dir; + const struct tcphdr *tcp; + const struct ipt_rpc_info *rpcinfo = matchinfo; + int port, portsok; + int tval; + + + DEBUGP("new packet to evaluate ..\n"); + + ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); + if (!ct) { + DEBUGP("no ct available [skip]\n"); + return 0; + } + + DEBUGP("ct detected. [cont]\n"); + dir = CTINFO2DIR(ctinfo); + + /* we only want the client to server packets for matching */ + if (dir != IP_CT_DIR_ORIGINAL) + return 0; + + /* This does sanity checking on UDP or TCP packets, + * like their respective modules. + */ + + switch (ct->tuplehash[0].tuple.dst.protonum) { + + case IPPROTO_UDP: + DEBUGP("PROTO_UDP [cont]\n"); + if (offset == 0 && datalen < sizeof(struct udphdr)) { + DEBUGP("packet does not contain a complete header. [drop]\n"); + return 0; + } + + for (port=0,portsok=0; port <= ports_n_c; port++) { + if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) { + portsok++; + break; + } + } + if (portsok == 0) { + DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n", + ntohs(ct->tuplehash[dir].tuple.dst.u.all)); + return 0; + } + + if ((datalen - sizeof(struct udphdr)) != 56) { + DEBUGP("packet length is not correct for RPC content. [skip]\n"); + if (rpcinfo->strict == 1) + *hotdrop = 1; + return 0; + } + DEBUGP("packet length is correct. [cont]\n"); + + /* Get to the data */ + data = (const u_int32_t *)hdr + 2; + + /* Check the RPC data */ + tval = check_rpc_packet(data, matchinfo, hotdrop, + dir, ct, offset, + request_p_list_udp); + + return tval; + + + case IPPROTO_TCP: + DEBUGP("PROTO_TCP [cont]\n"); + if (offset == 0 && datalen < sizeof(struct tcphdr)) { + DEBUGP("packet does not contain a complete header. [drop]\n"); + return 0; + } + + for (port=0,portsok=0; port <= ports_n_c; port++) { + if (ntohs(ct->tuplehash[dir].tuple.dst.u.all) == ports[port]) { + portsok++; + break; + } + } + if (portsok == 0) { + DEBUGP("packet is not destined for a portmapper [%u]. [skip]\n", + ntohs(ct->tuplehash[dir].tuple.dst.u.all)); + return 0; + } + + tcp = hdr; + if (datalen == (tcp->doff * 4)) { + DEBUGP("packet does not contain any data. [match]\n"); + return (1 && (!offset)); + } + + /* Tests if packet len is ok */ + if ((datalen - (tcp->doff * 4)) != 60) { + DEBUGP("packet length is not correct for RPC content. [skip]\n"); + if(rpcinfo->strict == 1) + *hotdrop = 1; + return 0; + } + DEBUGP("packet length is correct. [cont]\n"); + + /* Get to the data */ + data = (const u_int32_t *)tcp + tcp->doff + 1; + + /* Check the RPC data */ + tval = check_rpc_packet(data, matchinfo, hotdrop, + dir, ct, offset, + request_p_list_tcp); + + return tval; + + } + + DEBUGP("transport protocol=%u, is not supported [skip]\n", + ct->tuplehash[0].tuple.dst.protonum); + return 0; +} + + +static int checkentry(const char *tablename, const struct ipt_ip *ip, void *matchinfo, + unsigned int matchsize, unsigned int hook_mask) +{ + if (hook_mask + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD) | (1 << NF_IP_POST_ROUTING) + | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_LOCAL_OUT))) { + printk("ipt_rpc: only valid for PRE_ROUTING, FORWARD, POST_ROUTING, LOCAL_IN and/or LOCAL_OUT targets.\n"); + return 0; + } + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_rpc_info))) + return 0; + + return 1; +} + + +static struct ipt_match rpc_match = { { NULL, NULL }, "rpc", + &match, &checkentry, NULL, + THIS_MODULE }; + + +static int __init init(void) +{ + int port; + + DEBUGP("incrementing usage counts\n"); + __MOD_INC_USE_COUNT(ip_conntrack_rpc_udp); + __MOD_INC_USE_COUNT(ip_conntrack_rpc_tcp); + + /* If no port given, default to standard RPC port */ + if (ports[0] == 0) + ports[0] = RPC_PORT; + + DEBUGP("registering match [%s] for;\n", rpc_match.name); + for (port = 0; (port < MAX_PORTS) && ports[port]; port++) { + DEBUGP(" port %i (UDP|TCP);\n", ports[port]); + ports_n_c++; + } + + return ipt_register_match(&rpc_match); +} + + +static void fini(void) +{ + DEBUGP("unregistering match\n"); + ipt_unregister_match(&rpc_match); + + DEBUGP("decrementing usage counts\n"); + __MOD_DEC_USE_COUNT(ip_conntrack_rpc_tcp); + __MOD_DEC_USE_COUNT(ip_conntrack_rpc_udp); +} + + +module_init(init); +module_exit(fini); + diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_sctp.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_sctp.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_sctp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_sctp.c 2003-12-10 23:13:25.745162224 +0100 @@ -0,0 +1,125 @@ +/* IP tables module for matching the SCTP header + * + * $ipt_sctp.c,v 1.3 2002/05/29 15:09:00 laforge Exp$ + * + * (C) 2003 by Harald Welte + * + * This software is distributed under the terms GNU GPL v2 + */ + +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IP tables SCTP matching module"); +MODULE_LICENSE("GPL"); + +/* Returns 1 if the port is matched by the range, 0 otherwise */ +static inline int +port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert) +{ + int ret; + + ret = (port >= min && port <= max) ^ invert; + return ret; +} + +static int chunk_match(const struct sk_buff *skb, u_int32_t chunks, u_int32_t chunk_mask) +{ + sctp_chunkhdr_t *ch = (sctp_chunkhdr_t *) skb->data; + + u_int32_t chunks_present = 0; + + do { + u_int8_t *ch_end; + ch_end = ((u_int8_t *) ch) + WORD_ROUND(ntohs(ch->length)); + + if (ch->type < 32) + chunks_present |= (1 << ch_type); + else if (ch->type == SCTP_CID_ASCONF) + chunks_present |= (1 << 31); + else if (ch->type == SCTP_CID_ASCONF_ACK) + chunks_present |= (1 << 30); + + ch = (sctp_chunkhdr_t *) ch_end; + } while (ch_end < skb->tail); + + return ((chunks_present& chunk_mask) == chunks); +} + +static int match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, + int offset, const void *hdr, u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_sctp_info *info = matchinfo; + const struct iphdr *iph = skb->nh.iph; + const struct sctphdr *sh = (struct sctphdr *) skb->h.raw; + + if (iph->protocol != IPPROTO_SCTP) + return 0; + + if (offset == 1) { + duprintf("Dropping evil SCTP offset=1 frag.\n"); + *hotdrop = 1; + return 0; + } else if (offset == 0 && datalen < sizeof(struct sctphdr)) { + /* We've been askd o examine this packet, and we can't. + * Hence, no choice but to drop. */ + duprintf("Dropping evil SCTP offset=0 tinygram.\n"); + *hotdrop = 1; + return 0; + } + + return (!offset + && port_match(info->spts[0], info->spts[1], + ntohs(sh->source), + !!(info->invflags & IPT_SCTP_INV_SRCPT)) + && port_match(info->dpts[0], info->dpts[1], + ntohs(sh->dest), + !!(info->invflags & IPT_SCTP_INV_DSTPT)) + && chunk_match(skb, info->chunks, info->chunk_mask) + ); +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + const struct ipt_sctp_info *info = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_sctp_info))) + return 0; + + if (ip->proto != IPPROTO_SCTP && !(ip->invflags & IPT_INV_PROTO)) + return 0; + + if !(info->invflags & ~IPT_SCTP_INV_MASK) + return 0; + + return 1; +} + +static struct ipt_match sctp_match = { + .name = "sctp", + .match = &match, + .checkentry = &checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ipt_register_match(&sctp_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&sctp_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_state.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_state.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_state.c 2003-11-26 21:46:07.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_state.c 2003-12-10 23:13:24.664326536 +0100 @@ -23,10 +23,12 @@ enum ip_conntrack_info ctinfo; unsigned int statebit; - if (!ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) - statebit = IPT_STATE_INVALID; - else + if (skb->nfct == &ip_conntrack_untracked.infos[IP_CT_NEW]) + statebit = IPT_STATE_UNTRACKED; + else if (ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) statebit = IPT_STATE_BIT(ctinfo); + else + statebit = IPT_STATE_INVALID; return (sinfo->statemask & statebit); } diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_string.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_string.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_string.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_string.c 2003-12-10 23:14:14.165801168 +0100 @@ -0,0 +1,218 @@ +/* Kernel module to match a string into a packet. + * + * Copyright (C) 2000 Emmanuel Roger + * + * ChangeLog + * 19.02.2002: Gianni Tedesco + * Fixed SMP re-entrancy problem using per-cpu data areas + * for the skip/shift tables. + * 02.05.2001: Gianni Tedesco + * Fixed kernel panic, due to overrunning boyer moore string + * tables. Also slightly tweaked heuristic for deciding what + * search algo to use. + * 27.01.2001: Gianni Tedesco + * Implemented Boyer Moore Sublinear search algorithm + * alongside the existing linear search based on memcmp(). + * Also a quick check to decide which method to use on a per + * packet basis. + */ + +#include +#include +#include +#include +#include + +#include +#include + +MODULE_LICENSE("GPL"); + +struct string_per_cpu { + int *skip; + int *shift; + int *len; +}; + +struct string_per_cpu *bm_string_data=NULL; + +/* Boyer Moore Sublinear string search - VERY FAST */ +char *search_sublinear (char *needle, char *haystack, int needle_len, int haystack_len) +{ + int M1, right_end, sk, sh; + int ended, j, i; + + int *skip, *shift, *len; + + /* use data suitable for this CPU */ + shift=bm_string_data[smp_processor_id()].shift; + skip=bm_string_data[smp_processor_id()].skip; + len=bm_string_data[smp_processor_id()].len; + + /* Setup skip/shift tables */ + M1 = right_end = needle_len-1; + for (i = 0; i < BM_MAX_HLEN; i++) skip[i] = needle_len; + for (i = 0; needle[i]; i++) skip[needle[i]] = M1 - i; + + for (i = 1; i < needle_len; i++) { + for (j = 0; j < needle_len && needle[M1 - j] == needle[M1 - i - j]; j++); + len[i] = j; + } + + shift[0] = 1; + for (i = 1; i < needle_len; i++) shift[i] = needle_len; + for (i = M1; i > 0; i--) shift[len[i]] = i; + ended = 0; + + for (i = 0; i < needle_len; i++) { + if (len[i] == M1 - i) ended = i; + if (ended) shift[i] = ended; + } + + /* Do the search*/ + while (right_end < haystack_len) + { + for (i = 0; i < needle_len && haystack[right_end - i] == needle[M1 - i]; i++); + if (i == needle_len) { + return haystack+(right_end - M1); + } + + sk = skip[haystack[right_end - i]]; + sh = shift[i]; + right_end = max(right_end - i + sk, right_end + sh); + } + + return NULL; +} + +/* Linear string search based on memcmp() */ +char *search_linear (char *needle, char *haystack, int needle_len, int haystack_len) +{ + char *k = haystack + (haystack_len-needle_len); + char *t = haystack; + + while ( t <= k ) { + if (memcmp(t, needle, needle_len) == 0) + return t; + t++; + } + + return NULL; +} + + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_string_info *info = matchinfo; + struct iphdr *ip = skb->nh.iph; + int hlen, nlen; + char *needle, *haystack; + proc_ipt_search search=search_linear; + + if ( !ip ) return 0; + + /* get lenghts, and validate them */ + nlen=info->len; + hlen=ntohs(ip->tot_len)-(ip->ihl*4); + if ( nlen > hlen ) return 0; + + needle=(char *)&info->string; + haystack=(char *)ip+(ip->ihl*4); + + /* The sublinear search comes in to its own + * on the larger packets */ + if ( (hlen>IPT_STRING_HAYSTACK_THRESH) && + (nlen>IPT_STRING_NEEDLE_THRESH) ) { + if ( hlen < BM_MAX_HLEN ) { + search=search_sublinear; + }else{ + if (net_ratelimit()) + printk(KERN_INFO "ipt_string: Packet too big " + "to attempt sublinear string search " + "(%d bytes)\n", hlen ); + } + } + + return ((search(needle, haystack, nlen, hlen)!=NULL) ^ info->invert); +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + + if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info))) + return 0; + + return 1; +} + +void string_freeup_data(void) +{ + int c; + + if ( bm_string_data ) { + for(c=0; c. + * + * Copyright (c) 2002 Aaron Hopkins + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Goal: + * - Allow incoming TCP connections to be established. + * - Passing data should result in the connection being switched to the + * persist state (0 byte window), in which the remote side stops sending + * data and asks to continue every 60 seconds. + * - Attempts to shut down the connection should be ignored completely, so + * the remote side ends up having to time it out. + * + * This means: + * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes + * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing + * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited + */ + +#include +#include +#include +#include +#include +#include +#include +struct in_device; +#include +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + + +/* Stolen from ip_finish_output2 */ +static int ip_direct_send(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; + + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + return hh->hh_output(skb); + } else if (dst->neighbour) + return dst->neighbour->output(skb); + + if (net_ratelimit()) + printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n"); + kfree_skb(skb); + return -EINVAL; +} + + +/* Send reply */ +static void tarpit_tcp(struct sk_buff *oskb,struct rtable *ort,int local) +{ + struct sk_buff *nskb; + struct rtable *nrt; + struct tcphdr *otcph, *ntcph; + unsigned int otcplen; + u_int16_t tmp; + + /* A truncated TCP header isn't going to be useful */ + if (oskb->len < (oskb->nh.iph->ihl*4) + sizeof(struct tcphdr)) + return; + + otcph = (struct tcphdr *)((u_int32_t*)oskb->nh.iph + + oskb->nh.iph->ihl); + otcplen = oskb->len - oskb->nh.iph->ihl*4; + + /* No replies for RST or FIN */ + if (otcph->rst || otcph->fin) + return; + + /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */ + if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ))) + return; + + /* Check checksum. */ + if (tcp_v4_check(otcph, otcplen, oskb->nh.iph->saddr, + oskb->nh.iph->daddr, + csum_partial((char *)otcph, otcplen, 0)) != 0) + return; + + /* Copy skb (even if skb is about to be dropped, we can't just + clone it because there may be other things, such as tcpdump, + interested in it) */ + nskb = skb_copy(oskb, GFP_ATOMIC); + if (!nskb) + return; + + /* This packet will not be the same as the other: clear nf fields */ + nf_conntrack_put(nskb->nfct); + nskb->nfct = NULL; + nskb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + nskb->nf_debug = 0; +#endif + + ntcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); + + /* Truncate to length (no data) */ + ntcph->doff = sizeof(struct tcphdr)/4; + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); + nskb->nh.iph->tot_len = htons(nskb->len); + + /* Swap source and dest */ + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); + tmp = ntcph->source; + ntcph->source = ntcph->dest; + ntcph->dest = tmp; + + /* Use supplied sequence number or make a new one */ + ntcph->seq = otcph->ack ? otcph->ack_seq + : htonl(secure_tcp_sequence_number(nskb->nh.iph->saddr, + nskb->nh.iph->daddr, + ntcph->source, + ntcph->dest)); + + /* Our SYN-ACKs must have a >0 window */ + ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0; + + ntcph->urg_ptr = 0; + + /* Reset flags */ + ((u_int8_t *)ntcph)[13] = 0; + + if (otcph->syn && otcph->ack) { + ntcph->rst = 1; + ntcph->ack_seq = 0; + } else { + ntcph->syn = otcph->syn; + ntcph->ack = 1; + ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn); + } + + /* Adjust TCP checksum */ + ntcph->check = 0; + ntcph->check = tcp_v4_check(ntcph, sizeof(struct tcphdr), + nskb->nh.iph->saddr, + nskb->nh.iph->daddr, + csum_partial((char *)ntcph, + sizeof(struct tcphdr), 0)); + + /* Adjust IP TTL */ + nskb->nh.iph->ttl = sysctl_ip_default_ttl; + + /* Set DF, id = 0 */ + nskb->nh.iph->frag_off = htons(IP_DF); + nskb->nh.iph->id = 0; + + /* Adjust IP checksum */ + nskb->nh.iph->check = 0; + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, + nskb->nh.iph->ihl); + + if (ip_route_output(&nrt, nskb->nh.iph->daddr, + local ? nskb->nh.iph->saddr : 0, + RT_TOS(nskb->nh.iph->tos) | RTO_CONN, + 0) != 0) + goto free_nskb; + + dst_release(nskb->dst); + nskb->dst = &nrt->u.dst; + + /* "Never happens" */ + if (nskb->len > nskb->dst->pmtu) + goto free_nskb; + + ip_direct_send (nskb); + + return; + + free_nskb: + kfree_skb(nskb); +} + + +static unsigned int tarpit(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + struct sk_buff *skb = *pskb; + struct rtable *rt = (struct rtable*)skb->dst; + + /* Do we have an input route cache entry? */ + if (!rt) + return NF_DROP; + + /* No replies to physical multicast/broadcast */ + if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST) + return NF_DROP; + + /* Now check at the protocol level */ + if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) + return NF_DROP; + + /* Our naive response construction doesn't deal with IP + options, and probably shouldn't try. */ + if (skb->nh.iph->ihl*4 != sizeof(struct iphdr)) + return NF_DROP; + + /* We aren't interested in fragments */ + if (skb->nh.iph->frag_off & htons(IP_OFFSET)) + return NF_DROP; + + tarpit_tcp(skb,rt,hooknum == NF_IP_LOCAL_IN); + + return NF_DROP; +} + + +static int check(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + /* Only allow these for input/forward packet filtering. */ + if (strcmp(tablename, "filter") != 0) { + DEBUGP("TARPIT: bad table %s'.\n", tablename); + return 0; + } + if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) + | (1 << NF_IP_FORWARD))) != 0) { + DEBUGP("TARPIT: bad hook mask %X\n", hook_mask); + return 0; + } + + /* Must specify that it's a TCP packet */ + if (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO)) { + DEBUGP("TARPIT: not valid for non-tcp\n"); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_tarpit_reg += { { NULL, NULL }, "TARPIT", tarpit, check, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_tarpit_reg)) + return -EINVAL; + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_tarpit_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_TCPLAG.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_TCPLAG.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_TCPLAG.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_TCPLAG.c 2003-12-10 23:14:16.741409616 +0100 @@ -0,0 +1,697 @@ +/* ipt_TCPLAG.c -- kernel module to implement TCPLAG target into netfilter + * Copyright (C) 2002 Telford Tendys + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * This collects packets and attempts to make them into pairs + * based on its own knowledge of how typical network conversations + * operate. Once it has a pair, it logs the time between them. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* + * We need one spinlock for the hash table. + */ +static spinlock_t hash_lock = SPIN_LOCK_UNLOCKED; + +typedef struct timeval timeval_T; + +/* + * Linked lists of events in the connection, + * these store the SEQ numbers and the newest is always + * at the start of the linked list, then they get older + * down to the end of the linked list (this is not perfect + * if packets get out of order but we don't worry about fine + * details like that). + * + * Matching any event wipes out that event and also all other + * events down the chain (i.e. all older events). + * This keeps the linked list as short as possible. + */ +typedef struct tcplag_event_S +{ + struct tcplag_event_S *next; + u16 source_port; + u16 dest_port; + u32 expected_ACK; + struct timeval stamp; +} tcplag_event_T; + +/* + * This stores the connection statistics + * We define connections more loosely than TCP/IP does, + * because we only consider the two hosts, not the ports + * Also, we list the host-pairs in low,high order which + * means that we don't care who originated the connection. + */ +typedef struct tcplag_hash_S +{ + u32 low_ip; + u32 high_ip; + struct timeval lag_l_SEQ_h_ACK; /* l sends some data and h acknowledges that (sum of lag times) */ + struct timeval lag_h_SEQ_l_ACK; /* h sends some data and l acknowledges that (sum of lag times) */ + tcplag_event_T *h_ACK_list; /* Try to match ACK packets coming from h in this list */ + tcplag_event_T *l_ACK_list; /* Try to match ACK packets coming from l in this list */ + time_t stamp; /* When this bucket got added to the table */ + u16 count_l_SEQ_h_ACK; /* Increment for each event */ + u16 count_h_SEQ_l_ACK; /* Increment for each event */ +} tcplag_hash_T; + +static tcplag_hash_T **hashtab = 0; +static u32 hashsize = 0; +static u16 max_seconds = 30; /* Empty a hash bucket after this time */ +static u32 reaper_ix = 0; + +static void divide_down( timeval_T *T, int c ) +{ + int remainder; + + T->tv_usec /= c; + remainder = T->tv_sec % c; /* Only works properly with positive numbers */ + remainder *= 1000000; + T->tv_usec == remainder; + T->tv_sec /= c; +} + +int diff_timeval( timeval_T *tv1, timeval_T *tv2 ) +{ + register long x; + + x = tv1->tv_sec - tv2->tv_sec; + if( x ) return( x ); + x = tv1->tv_usec - tv2->tv_usec; + return( x ); +} + +void sprint_timeval( char *buf, timeval_T *tv ) +{ + if( tv->tv_sec ) + sprintf( buf, "%lu%06lu", tv->tv_sec, tv->tv_usec ); + else + sprintf( buf, "%lu", tv->tv_usec ); +} + +/* + * This generates the log messages through printk() + * + * There is really no particular interest in the port numbers at this stage, + * they are only useful for matching up the request with the reply. + * The IP numbers are useful because some sites may be slower than others + * or may travel different routes, etc (OK, in theory changing the port number + * could also change the route but I don't like that sort of theory). + * + * The tags are: + * + * LIP= The IP number of the side with the lowest lag + * RIP= The IP number of the side with the highest lag + * LLAG= The average time (in us) between RIP->LIP SEQ and LIP->RIP ACK + * RLAG= The average time (in us) between LIP->RIP SEQ and RIP->LIP ACK + */ +static void output( tcplag_hash_T *H, int level, const char *prefix ) +{ + struct timeval ltm, rtm; + u32 local_ip, remote_ip; + char r_buf[ 20 ], l_buf[ 20 ]; +/* + * We can't make sense of a connection that only passes data one way, + * In principle, at least the SYN and FIN should go both ways so we + * should get a few hits for every connection. + */ + if( 0 == H->count_l_SEQ_h_ACK || 0 == H->count_h_SEQ_l_ACK ) return; +/* + * Calculate average times by dividing down + */ + divide_down( &H->lag_l_SEQ_h_ACK, H->count_l_SEQ_h_ACK ); + divide_down( &H->lag_h_SEQ_l_ACK, H->count_h_SEQ_l_ACK ); +/* + * Sort these two by the lag so the the local is always the short lag + */ + if( diff_timeval( &H->lag_l_SEQ_h_ACK, &H->lag_h_SEQ_l_ACK ) > 0 ) + { + local_ip = H->low_ip; + remote_ip = H->high_ip; + rtm.tv_sec = H->lag_l_SEQ_h_ACK.tv_sec; + rtm.tv_usec = H->lag_l_SEQ_h_ACK.tv_usec; + ltm.tv_sec = H->lag_h_SEQ_l_ACK.tv_sec; + ltm.tv_usec = H->lag_h_SEQ_l_ACK.tv_usec; + } + else + { + local_ip = H->high_ip; + remote_ip = H->low_ip; + ltm.tv_sec = H->lag_l_SEQ_h_ACK.tv_sec; + ltm.tv_usec = H->lag_l_SEQ_h_ACK.tv_usec; + rtm.tv_sec = H->lag_h_SEQ_l_ACK.tv_sec; + rtm.tv_usec = H->lag_h_SEQ_l_ACK.tv_usec; + } +/* + * Don't use a spinlock on the output, + * it is not guaranteed safe because some OTHER printk could + * split our log message so we want only one single printk. + * + * We use sprintf() to partially pre-digest the output + * + * Actually, neither this not the main netfilter LOG target is + * really safe from printk() overlap, basically syslog cannot + * be regarded as a guaranteed data output channel. It is good + * enough for most purposes. + */ + sprint_timeval( l_buf, <m ); + sprint_timeval( r_buf, &rtm ); + printk( "<%d>%sLIP=%u.%u.%u.%u RIP=%u.%u.%u.%u LLAG=%s RLAG=%s\n", + level & 7, prefix, + NIPQUAD( local_ip ), NIPQUAD( remote_ip ), + l_buf, r_buf ); +} + +/* + * The reaper rolls through the hash table looking for old. + * Log entries are only generated at the reaping time + * (which means all log entries are out-of-date) + */ +static void reaper( time_t now, int level, const char *prefix ) +{ + int i; + + now -= max_seconds; + if( !hashsize ) return; + if( !hashtab ) return; + for( i = 0; i < 10; i++ ) + { + if( ++reaper_ix >= hashsize ) reaper_ix = 0; + +// DEBUGP( KERN_WARNING "reaper checking %u\n", reaper_ix ); + + if( hashtab[ reaper_ix ]) + { + tcplag_hash_T *found = 0; + + spin_lock_bh( &hash_lock ); + if( hashtab[ reaper_ix ]) + { + if( now > hashtab[ reaper_ix ]->stamp ) + { + DEBUGP( KERN_WARNING "reaper found expired entry\n" ); + found = hashtab[ reaper_ix ]; + hashtab[ reaper_ix ] = 0; + } + } + spin_unlock_bh( &hash_lock ); + + if( found ) + { + output( found, level, prefix ); + kfree( found ); + } + } + } +} + +/* + * Convert the connection characteristics into a number + * (not including the timestamp) FIXME: this is a sucky hash function + */ +static u32 make_hash( tcplag_hash_T *connection ) +{ + register u32 r; + + r = connection->low_ip; + r += connection->high_ip; + return( r ); +} + +static int compare_connections( tcplag_hash_T *con1, tcplag_hash_T *con2 ) +{ + int x; + + x = con1->low_ip - con2->low_ip; if( x ) return( x ); + x = con1->high_ip - con2->high_ip; + return( x ); +} + +static int compare_events( tcplag_event_T *ev1, tcplag_event_T *ev2 ) +{ + int x; + + DEBUGP( "Comparing sequence %u to %u\n", ev1->expected_ACK, ev2->expected_ACK ); + x = ev1->expected_ACK - ev2->expected_ACK; + if( x ) return( x ); + DEBUGP( "Comparing source port %u to %u\n", ev1->source_port, ev2->source_port ); + x = ev1->source_port - ev2->source_port; + if( x ) return( x ); + DEBUGP( "Comparing destination port %u to %u\n", ev1->dest_port, ev2->dest_port ); + x = ev1->dest_port - ev2->dest_port; + return( x ); +} + +/* + * Go to the hash table and either find an existing connection that + * matches correctly or inject a new connection into the table. + * Once the connection is OK, chain the event onto the linked list. + */ +static void hash_insert( tcplag_hash_T *connection, tcplag_event_T *event, int direction ) +{ + u32 h, i; + + if( !event ) return; /* Just to be safe */ + if( !hashsize ) return; + if( !hashtab ) return; + + h = make_hash( connection ); + h %= hashsize; + + DEBUGP( KERN_WARNING "hash_insert( %u )\n", h ); + + spin_lock_bh( &hash_lock ); + for( i = 0; i < hashsize; i++, ({ if( ++h >= hashsize ) { h = 0; }})) + { + tcplag_hash_T *co_new = 0; +/* + * Consider existing entry + */ + if( hashtab[ h ]) + { + if( compare_connections( hashtab[ h ], connection )) continue; + co_new = hashtab[ h ]; + DEBUGP( KERN_WARNING "Existing connection at %u\n", h ); + goto add_link; + } +/* + * Use empty slot for new entry + */ + if( !hashtab[ h ]) + { + co_new = kmalloc( sizeof( tcplag_hash_T ), GFP_ATOMIC ); + memset( co_new, 0, sizeof( tcplag_hash_T )); + co_new->low_ip = connection->low_ip; + co_new->high_ip = connection->high_ip; + co_new->stamp = event->stamp.tv_sec; + hashtab[ h ] = co_new; + DEBUGP( KERN_WARNING "Added connection to table at %u\n", h ); + add_link: + { + tcplag_event_T *ev_new; + + ev_new = kmalloc( sizeof( tcplag_event_T ), GFP_ATOMIC ); + memcpy( ev_new, event, sizeof( tcplag_event_T )); + if( direction ) + { + ev_new->next = co_new->h_ACK_list; + co_new->h_ACK_list = ev_new; + DEBUGP( KERN_WARNING "Connection at %u, direction is h_ACK_list\n", h ); + } + else + { + ev_new->next = co_new->l_ACK_list; + co_new->l_ACK_list = ev_new; + DEBUGP( KERN_WARNING "Connection at %u, direction is l_ACK_list\n", h ); + } + } + goto done; + } + } + done: + spin_unlock_bh( &hash_lock ); +} + +/* + * Search the hash table for a matching connection, + * if we can't find one of those then we are stuffed. + * + * Once a connection has been found, scan along the list for + * a matching SEQ number and if that is found then calculate + * the lag, update the counters and cut the chain at the + * point where the matching SEQ is found. + */ +static int request_complete( tcplag_hash_T *connection, tcplag_event_T *event, int direction ) +{ + u32 h, i; + + if( !event ) return( 0 ); + if( !hashsize ) return( 0 ); + if( !hashtab ) return( 0 ); + h = make_hash( connection ); + h %= hashsize; + + DEBUGP( KERN_WARNING "request_complete( %u )\n", h ); + + for( i = 0; i < hashsize; i++ ) + { + tcplag_hash_T *found = 0; + + if( !hashtab[ h ]) return( 0 ); + + spin_lock_bh( &hash_lock ); + if( hashtab[ h ]) + { + if( !compare_connections( hashtab[ h ], connection )) + { + tcplag_event_T *ev, **evroot; + timeval_T *tv; + u16 *cn; + + found = hashtab[ h ]; + if( direction ) + { + evroot = &found->h_ACK_list; + tv = &found->lag_l_SEQ_h_ACK; + cn = &found->count_l_SEQ_h_ACK; + DEBUGP( KERN_WARNING "Connection at %u, direction is h_ACK_list\n", h ); + } + else + { + evroot = &found->l_ACK_list; + tv = &found->lag_h_SEQ_l_ACK; + cn = &found->count_h_SEQ_l_ACK; + DEBUGP( KERN_WARNING "Connection at %u, direction is l_ACK_list\n", h ); + } + for( ev = *evroot; ev; ev = ev->next ) + { + if( !compare_events( ev, event )) + { +/* + * Calculate the lag (in two parts) and add that to the collection + */ + event->stamp.tv_sec -= ev->stamp.tv_sec; + event->stamp.tv_usec -= ev->stamp.tv_usec; + if( event->stamp.tv_usec < 0 ) + { + event->stamp.tv_usec += 1000000; + event->stamp.tv_sec++; + } + if( event->stamp.tv_sec < 0 ) + { + DEBUGP( KERN_WARNING "Negative lag detected\n" ); + } + else + { + tv->tv_sec += event->stamp.tv_sec; + tv->tv_usec += event->stamp.tv_usec; + ++*cn; + DEBUGP( KERN_WARNING "Found a match, added %lu.%06lu" + " (accumulator is up to %lu.%06lu, %u events)\n", + event->stamp.tv_sec, + event->stamp.tv_usec, + tv->tv_sec, tv->tv_usec, *cn ); + } +/* + * Truncate the linked list. + * + * Visit each event in the list and return the memory to the pool. + * + * If a host is making multiple connections to the same remote host + * then this truncation will result in some requests not being + * monitored. Statistically we will still get some reasonable number + * of measurements and multiple simultaneous connections between host + * pairs don't happen all that often. + */ + *evroot = 0; + while( ev ) + { + tcplag_event_T *ev_next = ev->next; + DEBUGP( KERN_WARNING "Shitcan %u\n", ev->expected_ACK ); + kfree( ev ); + ev = ev_next; + } +/* + * TODO: overflow limit for *cn, force premature output() if necessary + * (and drop this connection from the hash table) + */ + break; + } + } + goto done; + } + } + done: + spin_unlock_bh( &hash_lock ); + + if( found ) return( 1 ); + if( ++h >= hashsize ) h = 0; + } + return( 0 ); +} + +/* + * Here is our target data: + * + * pskb -- The packet itself (see linux/skbuff.h for breakdown) + * + * hooknum -- + * + * in -- The device that this packet came in on + * (depending on the chain this may or may not exist) + * + * out -- The device that this packet is just about to go + * out onto (again existance depends on the chain) + * + * targinfo -- Our private data (handed through from iptables command util) + * + * userinfo -- Some more data + * + */ + +static unsigned int target( struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo ) +{ + struct iphdr *iph = ( *pskb )->nh.iph; + const struct ipt_tcplag *el = targinfo; + tcplag_hash_T connection; + tcplag_event_T event; + int direction; +/* + * We know we are dealing with IP here + * Fill in all the obvious fields + */ + if( iph->saddr > iph->daddr ) + { + direction = 0; + connection.high_ip = iph->saddr; + connection.low_ip = iph->daddr; + } + else + { + direction = 1; + connection.low_ip = iph->saddr; + connection.high_ip = iph->daddr; + } + do_gettimeofday( &event.stamp ); +/* + * Do a bit of cleaning + */ + reaper( event.stamp.tv_sec, el->level, el->prefix ); + + DEBUGP( KERN_WARNING "got packet %lu %lu %s %s\n", + event.stamp.tv_sec, + event.stamp.tv_usec, + in ? in->name : "none", out ? out->name : "none" ); +/* + * Now start looking at the details + * + * First step is to identify this packet to see if it is + * the sort of packet that we are interested in. + * Don't hold any locks while we are doing this because often + * we will just let the packet go without any further consideration. + */ + switch( iph->protocol ) + { + case IPPROTO_TCP: + { + struct tcphdr *tcp; + + if( ntohs( iph->frag_off ) & IP_OFFSET ) + { + DEBUGP( KERN_WARNING "ignoring fragment\n" ); + break; + } + tcp = (struct tcphdr *)((u32 *)iph + iph->ihl ); + event.source_port = ntohs( tcp->source ); + event.dest_port = ntohs( tcp->dest ); +/* + * Every packet should have a valid SEQ number so use this to + * generate an ACK number. This works along the formula: + * -- Start with the SEQ number + * -- For SYN or FIN add 1 to that number + * -- For data packet, add the data length to that number + */ + +/* + * Data length requires a bit of fiddling around + */ + { + unsigned int data_len; + if( tcp->syn || tcp->fin ) + { + data_len = 1; /* Not real data, the SEQ clicks forward by 1 */ + } + else + { + data_len = ntohs( iph->tot_len ); + data_len -= 4 * iph->ihl; /* Subtract away IP header & options */ + data_len -= 4 * tcp->doff; /* Subtract away TCP header & options */ + } + + DEBUGP( KERN_WARNING "Data length calculated at %u\n", data_len ); + + if( data_len ) /* Only track events that demand an ACK */ + { + event.expected_ACK = ntohl( tcp->seq ) + data_len; + hash_insert( &connection, &event, direction ); + } + else + { + DEBUGP( "Don't bother to insert this, ACK not required\n" ); + } + } + + if( tcp->ack ) + { +/* + * Now we consider the matching of an existing event. + * Reverse the port numbers and change the ACK number to the actual ACK number + * Note that the direction is reversed because the reply will be going + * the opposite way to the request. + */ + event.expected_ACK = ntohl( tcp->ack_seq ); + event.dest_port = ntohs( tcp->source ); + event.source_port = ntohs( tcp->dest ); + request_complete( &connection, &event, !direction ); + } + else + { + DEBUGP( "Don't bother to check this, ACK not valid\n" ); + } + } + } + return( IPT_CONTINUE ); +} + +/* + * return( 0 ) if there is a problem with this entry (i.e. kick it out of the kernel) + * return( 1 ) if the entry is suitable + * + * tablename -- + * + * e -- + * + * targinfo -- Our private data block (handed to us from iptables plug-in) + * + * targinfosize -- The size of our private data block + * + * hook_mask -- + * + * + * Not much can go wrong for us, any illegal flags are harmlessly ignored, + * all possible flag combos make sense. All we check for is correct data size. + */ +static int checkentry( const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask ) +{ + const struct ipt_tcplag *el = targinfo; + + if( targinfosize != IPT_ALIGN( sizeof( struct ipt_tcplag ))) + { + DEBUGP( "TCPLAG: targinfosize %u != %u\n", targinfosize, + IPT_ALIGN( sizeof( struct ipt_tcplag ))); + return( 0 ); + } + if( el->prefix[ 14 ]) return( 0 ); /* Be sure to have terminated string */ + return( 1 ); +} + +static struct ipt_target reg = +{ + { 0, 0 }, + "TCPLAG", + &target, + &checkentry, + 0, + THIS_MODULE +}; + +static int __init init( void ) +{ + if( ipt_register_target( ® )) return( -EINVAL ); + hashsize = 123; /* should be configurable */ + hashtab = kmalloc( sizeof( void * ) * hashsize, GFP_ATOMIC ); + memset( hashtab, 0, sizeof( void * ) * hashsize ); + return( 0 ); +} + +/* + * This should not need locks (in theory) + * because it can only get punted after it is no longer + * chained into any of the netfilter lists. + */ +static void __exit fini( void ) +{ + int i; + + ipt_unregister_target( ® ); +/* + * Put back kernel memory + */ + for( i = 0; i < hashsize; i++ ) + { + tcplag_hash_T *p; + + if(( p = hashtab[ i ])) + { + tcplag_event_T *ev, *evn; + + hashtab[ i ] = 0; + for( ev = p->h_ACK_list; ev; ev = evn ) + { + evn = ev->next; + kfree( ev ); + } + for( ev = p->l_ACK_list; ev; ev = evn ) + { + evn = ev->next; + kfree( ev ); + } + kfree( p ); + } + } + kfree( hashtab ); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_time.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_time.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_time.c 2003-12-10 23:13:47.815806976 +0100 @@ -0,0 +1,185 @@ +/* + This is a module which is used for time matching + It is using some modified code from dietlibc (localtime() function) + that you can find at http://www.fefe.de/dietlibc/ + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL + 2001-05-04 Fabrice MARIE : initial development. + 2001-21-05 Fabrice MARIE : bug fix in the match code, + thanks to "Zeng Yu" for bug report. + 2001-26-09 Fabrice MARIE : force the match to be in LOCAL_IN or PRE_ROUTING only. + 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack, + added Nguyen Dang Phuoc Dong patch to support timezones. +*/ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Fabrice MARIE "); +MODULE_DESCRIPTION("Match arrival timestamp"); +MODULE_LICENSE("GPL"); + +struct tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + + long int tm_gmtoff; /* we don't care, we count from GMT */ + const char *tm_zone; /* we don't care, we count from GMT */ +}; + +void +localtime(const time_t *timepr, struct tm *r); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_time_info *info = matchinfo; /* match info for rule */ + struct tm currenttime; /* time human readable */ + u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1}; + u_int16_t packet_time; + struct timeval kerneltimeval; + time_t packet_local_time; + + /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */ + if (info->kerneltime) + { + do_gettimeofday(&kerneltimeval); + packet_local_time = kerneltimeval.tv_sec; + } + else + packet_local_time = skb->stamp.tv_sec; + + /* Transform the timestamp of the packet, in a human readable form */ + localtime(&packet_local_time, ¤ttime); + + /* check if we match this timestamp, we start by the days... */ + if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) + return 0; /* the day doesn't match */ + + /* ... check the time now */ + packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min; + if ((packet_time < info->time_start) || (packet_time > info->time_stop)) + return 0; + + /* here we match ! */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_time_info *info = matchinfo; /* match info for rule */ + + /* First, check that we are in the correct hook */ + /* PRE_ROUTING, LOCAL_IN or FROWARD */ + if (hook_mask + & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) + { + printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n"); + return 0; + } + /* we use the kerneltime if we are in forward or output */ + info->kerneltime = 1; + if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) + /* if not, we use the skb time */ + info->kerneltime = 0; + + /* Check the size */ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info))) + return 0; + /* Now check the coherence of the data ... */ + if ((info->time_start > 1439) || /* 23*60+59 = 1439*/ + (info->time_stop > 1439)) + { + printk(KERN_WARNING "ipt_time: invalid argument\n"); + return 0; + } + + return 1; +} + +static struct ipt_match time_match += { { NULL, NULL }, "time", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + printk("ipt_time loading\n"); + return ipt_register_match(&time_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&time_match); + printk("ipt_time unloaded\n"); +} + +module_init(init); +module_exit(fini); + + +/* The part below is borowed and modified from dietlibc */ + +/* seconds per day */ +#define SPD 24*60*60 + +void +localtime(const time_t *timepr, struct tm *r) { + time_t i; + time_t timep; + extern struct timezone sys_tz; + const unsigned int __spm[12] = + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + }; + register time_t work; + + timep = (*timepr) - (sys_tz.tz_minuteswest * 60); + work=timep%(SPD); + r->tm_sec=work%60; work/=60; + r->tm_min=work%60; r->tm_hour=work/60; + work=timep/(SPD); + r->tm_wday=(4+work)%7; + for (i=1970; ; ++i) { + register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365; + if (work>k) + work-=k; + else + break; + } + r->tm_year=i-1900; + for (i=11; i && __spm[i]>work; --i) ; + r->tm_mon=i; + r->tm_mday=work-__spm[i]+1; +} diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_TRACE.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_TRACE.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_TRACE.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_TRACE.c 2003-12-10 23:13:24.663326688 +0100 @@ -0,0 +1,67 @@ +/* This is a module which is used for setting + * the NFC_TRACE flag in the nfcache field of an skb. + */ +#include +#include + +#include + +static unsigned int +target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, + void *userinfo) +{ + (*pskb)->nfcache |= NFC_TRACE; + return IPT_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (targinfosize != 0) { + printk(KERN_WARNING "TRACE: targinfosize %u != 0\n", + targinfosize); + return 0; + } + + if (strcmp(tablename, "raw") != 0) { + printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_trace_reg = { + .name = "TRACE", + .target = target, + .checkentry = checkentry, + .destroy = NULL, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + if (ipt_register_target(&ipt_trace_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_trace_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_DESCRIPTION("IPv4 TRACE target"); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_TTL.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_TTL.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_TTL.c 2003-12-10 23:13:48.933637040 +0100 @@ -0,0 +1,110 @@ +/* TTL modification target for IP tables + * (C) 2000 by Harald Welte + * + * Version: 1.8 + * + * This software is distributed under the terms of GNU GPL + */ + +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Harald Welte "); +MODULE_DESCRIPTION("IP tables TTL modification module"); +MODULE_LICENSE("GPL"); + +static unsigned int ipt_ttl_target(struct sk_buff **pskb, unsigned int hooknum, + const struct net_device *in, const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct iphdr *iph = (*pskb)->nh.iph; + const struct ipt_TTL_info *info = targinfo; + u_int16_t diffs[2]; + int new_ttl; + + switch (info->mode) { + case IPT_TTL_SET: + new_ttl = info->ttl; + break; + case IPT_TTL_INC: + new_ttl = iph->ttl + info->ttl; + if (new_ttl > 255) + new_ttl = 255; + break; + case IPT_TTL_DEC: + new_ttl = iph->ttl + info->ttl; + if (new_ttl < 0) + new_ttl = 0; + break; + default: + new_ttl = iph->ttl; + break; + } + + if (new_ttl != iph->ttl) { + diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF; + iph->ttl = new_ttl; + diffs[1] = htons(((unsigned)iph->ttl) << 8); + iph->check = csum_fold(csum_partial((char *)diffs, + sizeof(diffs), + iph->check^0xFFFF)); + (*pskb)->nfcache |= NFC_ALTERED; + } + + return IPT_CONTINUE; +} + +static int ipt_ttl_checkentry(const char *tablename, + const struct ipt_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_TTL_info *info = targinfo; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) { + printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n", + targinfosize, + IPT_ALIGN(sizeof(struct ipt_TTL_info))); + return 0; + } + + if (strcmp(tablename, "mangle")) { + printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if (info->mode > IPT_TTL_MAXMODE) { + printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", + info->mode); + return 0; + } + + if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) { + printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n"); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_TTL = { { NULL, NULL }, "TTL", + ipt_ttl_target, ipt_ttl_checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&ipt_TTL); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_TTL); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_u32.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_u32.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_u32.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_u32.c 2003-12-10 23:13:50.006473944 +0100 @@ -0,0 +1,211 @@ +/* Kernel module to match u32 packet content. */ + +/* +U32 tests whether quantities of up to 4 bytes extracted from a packet +have specified values. The specification of what to extract is general +enough to find data at given offsets from tcp headers or payloads. + + --u32 tests + The argument amounts to a program in a small language described below. + tests := location = value | tests && location = value + value := range | value , range + range := number | number : number + a single number, n, is interpreted the same as n:n + n:m is interpreted as the range of numbers >=n and <=m + location := number | location operator number + operator := & | << | >> | @ + + The operators &, <<, >>, && mean the same as in c. The = is really a set + membership operator and the value syntax describes a set. The @ operator + is what allows moving to the next header and is described further below. + + *** Until I can find out how to avoid it, there are some artificial limits + on the size of the tests: + - no more than 10 ='s (and 9 &&'s) in the u32 argument + - no more than 10 ranges (and 9 commas) per value + - no more than 10 numbers (and 9 operators) per location + + To describe the meaning of location, imagine the following machine that + interprets it. There are three registers: + A is of type char*, initially the address of the IP header + B and C are unsigned 32 bit integers, initially zero + + The instructions are: + number B = number; + C = (*(A+B)<<24)+(*(A+B+1)<<16)+(*(A+B+2)<<8)+*(A+B+3) + &number C = C&number + <>number C = C>>number + @number A = A+C; then do the instruction number + Any access of memory outside [skb->head,skb->end] causes the match to fail. + Otherwise the result of the computation is the final value of C. + + Whitespace is allowed but not required in the tests. + However the characters that do occur there are likely to require + shell quoting, so it's a good idea to enclose the arguments in quotes. + +Example: + match IP packets with total length >= 256 + The IP header contains a total length field in bytes 2-3. + --u32 "0&0xFFFF=0x100:0xFFFF" + read bytes 0-3 + AND that with FFFF (giving bytes 2-3), + and test whether that's in the range [0x100:0xFFFF] + +Example: (more realistic, hence more complicated) + match icmp packets with icmp type 0 + First test that it's an icmp packet, true iff byte 9 (protocol) = 1 + --u32 "6&0xFF=1 && ... + read bytes 6-9, use & to throw away bytes 6-8 and compare the result to 1 + Next test that it's not a fragment. + (If so it might be part of such a packet but we can't always tell.) + n.b. This test is generally needed if you want to match anything + beyond the IP header. + The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete + packet (not a fragment). Alternatively, you can allow first fragments + by only testing the last 5 bits of byte 6. + ... 4&0x3FFF=0 && ... + Last test: the first byte past the IP header (the type) is 0 + This is where we have to use the @syntax. The length of the IP header + (IHL) in 32 bit words is stored in the right half of byte 0 of the + IP header itself. + ... 0>>22&0x3C@0>>24=0" + The first 0 means read bytes 0-3, + >>22 means shift that 22 bits to the right. Shifting 24 bits would give + the first byte, so only 22 bits is four times that plus a few more bits. + &3C then eliminates the two extra bits on the right and the first four + bits of the first byte. + For instance, if IHL=5 then the IP header is 20 (4 x 5) bytes long. + In this case bytes 0-1 are (in binary) xxxx0101 yyzzzzzz, + >>22 gives the 10 bit value xxxx0101yy and &3C gives 010100. + @ means to use this number as a new offset into the packet, and read + four bytes starting from there. This is the first 4 bytes of the icmp + payload, of which byte 0 is the icmp type. Therefore we simply shift + the value 24 to the right to throw out all but the first byte and compare + the result with 0. + +Example: + tcp payload bytes 8-12 is any of 1, 2, 5 or 8 + First we test that the packet is a tcp packet (similar to icmp). + --u32 "6&0xFF=6 && ... + Next, test that it's not a fragment (same as above). + ... 0>>22&0x3C@12>>26&0x3C@8=1,2,5,8" + 0>>22&3C as above computes the number of bytes in the IP header. + @ makes this the new offset into the packet, which is the start of the + tcp header. The length of the tcp header (again in 32 bit words) is + the left half of byte 12 of the tcp header. The 12>>26&3C + computes this length in bytes (similar to the IP header before). + @ makes this the new offset, which is the start of the tcp payload. + Finally 8 reads bytes 8-12 of the payload and = checks whether the + result is any of 1, 2, 5 or 8 +*/ + +#include +#include + +#include +#include + +/* #include for timing */ + +MODULE_AUTHOR("Don Cohen "); +MODULE_DESCRIPTION("IP tables u32 matching module"); +MODULE_LICENSE("GPL"); + +static int +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + const struct ipt_u32 *data = matchinfo; + int testind, i; + unsigned char* origbase = (char*)skb->nh.iph; + unsigned char* base = origbase; + unsigned char* head = skb->head; + unsigned char* end = skb->end; + int nnums, nvals; + u_int32_t pos, val; + /* unsigned long long cycles1, cycles2, cycles3, cycles4; + cycles1 = get_cycles(); */ + + for (testind=0; testind < data->ntests; testind++) { + base = origbase; /* reset for each test */ + pos = data->tests[testind].location[0].number; + if (base+pos+3 > end || base+pos < head) + return 0; + val = (base[pos]<<24) + (base[pos+1]<<16) + + (base[pos+2]<<8) + base[pos+3]; + nnums = data->tests[testind].nnums; + for (i=1; i < nnums; i++) { + u_int32_t number = data->tests[testind].location[i].number; + switch (data->tests[testind].location[i].nextop) { + case IPT_U32_AND: + val = val & number; + break; + case IPT_U32_LEFTSH: + val = val << number; + break; + case IPT_U32_RIGHTSH: + val = val >> number; + break; + case IPT_U32_AT: + base = base + val; + pos = number; + if (base+pos+3 > end || base+pos < head) + return 0; + val = (base[pos]<<24) + (base[pos+1]<<16) + + (base[pos+2]<<8) + base[pos+3]; + break; + } + } + nvals = data->tests[testind].nvalues; + for (i=0; i < nvals; i++) { + if ((data->tests[testind].value[i].min <= val) && + (val <= data->tests[testind].value[i].max)) { + break; + } + } + if (i >= data->tests[testind].nvalues) { + /* cycles2 = get_cycles(); + printk("failed %d in %d cycles\n", testind, + cycles2-cycles1); */ + return 0; + } + } + /* cycles2 = get_cycles(); + printk("succeeded in %d cycles\n", cycles2-cycles1); */ + return 1; +} + +static int +checkentry(const char *tablename, + const struct ipt_ip *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + if (matchsize != IPT_ALIGN(sizeof(struct ipt_u32))) + return 0; + return 1; +} + +static struct ipt_match u32_match += { { NULL, NULL }, "u32", &match, &checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_match(&u32_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&u32_match); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ULOG.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_ULOG.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_ULOG.c 2003-11-26 21:43:34.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_ULOG.c 2003-12-10 23:13:22.346678872 +0100 @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -75,6 +76,10 @@ MODULE_PARM(flushtimeout, "i"); MODULE_PARM_DESC(flushtimeout, "buffer flush timeout"); +static unsigned int nflog = 1; +MODULE_PARM(nflog, "i"); +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); + /* global data structures */ typedef struct { @@ -152,17 +157,17 @@ return skb; } -static unsigned int ipt_ulog_target(struct sk_buff **pskb, - const struct net_device *in, - const struct net_device *out, - unsigned int hooknum, - const void *targinfo, void *userinfo) +static void ipt_ulog_packet(unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct ipt_ulog_info *loginfo, + const char *prefix) { ulog_buff_t *ub; ulog_packet_msg_t *pm; size_t size, copy_len; struct nlmsghdr *nlh; - struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; /* ffs == find first bit set, necessary because userspace * is already shifting groupnumber, but we need unshifted. @@ -171,8 +176,8 @@ /* calculate the size of the skb needed */ if ((loginfo->copy_range == 0) || - (loginfo->copy_range > (*pskb)->len)) { - copy_len = (*pskb)->len; + (loginfo->copy_range > skb->len)) { + copy_len = skb->len; } else { copy_len = loginfo->copy_range; } @@ -209,19 +214,21 @@ /* copy hook, prefix, timestamp, payload, etc. */ pm->data_len = copy_len; - pm->timestamp_sec = (*pskb)->stamp.tv_sec; - pm->timestamp_usec = (*pskb)->stamp.tv_usec; - pm->mark = (*pskb)->nfmark; + pm->timestamp_sec = skb->stamp.tv_sec; + pm->timestamp_usec = skb->stamp.tv_usec; + pm->mark = skb->nfmark; pm->hook = hooknum; - if (loginfo->prefix[0] != '\0') + if (prefix != NULL) + strncpy(pm->prefix, prefix, sizeof(pm->prefix)); + else if (loginfo->prefix[0] != '\0') strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); else *(pm->prefix) = '\0'; if (in && in->hard_header_len > 0 - && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph + && skb->mac.raw != (void *) skb->nh.iph && in->hard_header_len <= ULOG_MAC_LEN) { - memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len); + memcpy(pm->mac, skb->mac.raw, in->hard_header_len); pm->mac_len = in->hard_header_len; } else pm->mac_len = 0; @@ -236,8 +243,8 @@ else pm->outdev_name[0] = '\0'; - /* copy_len <= (*pskb)->len, so can't fail. */ - if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0) + /* copy_len <= skb->len, so can't fail. */ + if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0) BUG(); /* check if we are building multi-part messages */ @@ -261,8 +268,7 @@ UNLOCK_BH(&ulog_lock); - return IPT_CONTINUE; - + return; nlmsg_failure: PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); @@ -271,8 +277,35 @@ PRINTR("ipt_ULOG: Error building netlink message\n"); UNLOCK_BH(&ulog_lock); +} + +static unsigned int ipt_ulog_target(struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, void *userinfo) +{ + struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; - return IPT_CONTINUE; + ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, NULL); + + return IPT_CONTINUE; +} + +static void ipt_logfn(unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const char *prefix) +{ + struct ipt_ulog_info loginfo = { + .nl_group = NFLOG_DEFAULT_NLGROUP, + .copy_range = 0, + .qthreshold = NFLOG_DEFAULT_QTHRESHOLD, + .prefix = "" + }; + + ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix); } static int ipt_ulog_checkentry(const char *tablename, @@ -337,6 +370,9 @@ return -EINVAL; } + if (nflog) + nf_log_register(PF_INET, &ipt_logfn); + return 0; } @@ -347,6 +383,9 @@ DEBUGP("ipt_ULOG: cleanup_module\n"); + if (nflog) + nf_log_unregister(PF_INET, &ipt_logfn); + ipt_unregister_target(&ipt_ulog_reg); sock_release(nflognl->sk_socket); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_XOR.c linux-2.6.0-test11/net/ipv4/netfilter/ipt_XOR.c --- linux-2.6.0-test11.org/net/ipv4/netfilter/ipt_XOR.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/ipt_XOR.c 2003-12-10 23:14:18.224184200 +0100 @@ -0,0 +1,107 @@ +/* XOR target for IP tables + * (C) 2000 by Tim Vandermeersch + * Based on ipt_TTL.c + * + * Version 1.0 + * + * This software is distributed under the terms of GNU GPL + */ + +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Tim Vandermeersch "); +MODULE_DESCRIPTION("IP tables XOR module"); +MODULE_LICENSE("GPL"); + +static unsigned int ipt_xor_target(struct sk_buff **pskb, unsigned int hooknum, + const struct net_device *in, const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct ipt_XOR_info *info = (void *) targinfo; + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph; + struct udphdr *udph; + int i, j, k; + + if (iph->protocol == IPPROTO_TCP) { + tcph = (struct tcphdr *) ((*pskb)->data + iph->ihl*4); + for (i=0, j=0; i<(ntohs(iph->tot_len) - iph->ihl*4 - tcph->doff*4); ) { + for (k=0; k<=info->block_size; k++) { + (char) (*pskb)->data[ iph->ihl*4 + tcph->doff*4 + i ] ^= + info->key[j]; + i++; + } + j++; + if (info->key[j] == 0x00) + j = 0; + } + } else if (iph->protocol == IPPROTO_UDP) { + udph = (struct udphdr *) ((*pskb)->data + iph->ihl*4); + for (i=0, j=0; i<(ntohs(udph->len)-8); ) { + for (k=0; k<=info->block_size; k++) { + (char) (*pskb)->data[ iph->ihl*4 + sizeof(struct udphdr) + i ] ^= + info->key[j]; + i++; + } + j++; + if (info->key[j] == 0x00) + j = 0; + } + } + + return IPT_CONTINUE; +} + +static int ipt_xor_checkentry(const char *tablename, const struct ipt_entry *e, + void *targinfo, unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ipt_XOR_info *info = targinfo; + + if (targinfosize != IPT_ALIGN(sizeof(struct ipt_XOR_info))) { + printk(KERN_WARNING "XOR: targinfosize %u != %Zu\n", + targinfosize, IPT_ALIGN(sizeof(struct ipt_XOR_info))); + return 0; + } + + if (strcmp(tablename, "mangle")) { + printk(KERN_WARNING "XOR: can only be called from" + "\"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if (!strcmp(info->key, "")) { + printk(KERN_WARNING "XOR: You must specify a key"); + return 0; + } + + if (info->block_size == 0) { + printk(KERN_WARNING "XOR: You must specify a block-size"); + return 0; + } + + return 1; +} + +static struct ipt_target ipt_XOR = { { NULL, NULL }, "XOR", + ipt_xor_target, ipt_xor_checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ipt_register_target(&ipt_XOR); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_XOR); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/Kconfig linux-2.6.0-test11/net/ipv4/netfilter/Kconfig --- linux-2.6.0-test11.org/net/ipv4/netfilter/Kconfig 2003-11-26 21:45:21.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/Kconfig 2003-12-10 23:13:25.745162224 +0100 @@ -197,6 +197,15 @@ To compile it as a module, choose M here. If unsure, say N. +config IP_NF_MATCH_SCTP + tristate "SCTP match support" + depends on IP_NF_IPTABLES + help + This match allows iptables to match on the SCTP header. + + If you want to compile it as a module, say M here and read + . If unsure, say `N'. + config IP_NF_MATCH_LENGTH tristate "LENGTH match support" depends on IP_NF_IPTABLES @@ -527,6 +536,42 @@ To compile it as a module, choose M here. If unsure, say N. +config IP_NF_RAW + tristate "Raw table" + depends on IP_NF_IPTABLES + help + This option adds a `raw' table to iptables: see the man page for + iptables(8). This table is the very first in the netfilter + framework and hooks in at the PREROUTING and OUTPUT chains. + The TRACE and NOTRACK targets can be used in this table only. + + To compile it as a module, choose M here. If unsure, say N. + +config IP_NF_TARGET_TRACE + tristate "TRACE target support" + depends on IP_NF_RAW + help + The TRACE target allows packets to be traced as those matches + any subsequent rule in any table/rule. The matched rule and + the packet is logged with the prefix + + TRACE: tablename/chainname/rulenum + + if the ipt_LOG or ipt_ULOG targets are loaded in. + + To compile it as a module, choose M here. If unsure, say N. + +config IP_NF_TARGET_NOTRACK + tristate "NOTRACK target support" + depends on IP_NF_RAW + help + The NOTRACK target allows a select rule to specify which + packets *not* to enter the conntrack/NAT subsystems + with all the consequences (no ICMP error tracking, + no protocol helpers for the selected packets). + + To compile it as a module, choose M here. If unsure, say N. + config IP_NF_ARPTABLES tristate "ARP tables support" diff -Nur linux-2.6.0-test11.org/net/ipv4/netfilter/Makefile linux-2.6.0-test11/net/ipv4/netfilter/Makefile --- linux-2.6.0-test11.org/net/ipv4/netfilter/Makefile 2003-11-26 21:43:25.000000000 +0100 +++ linux-2.6.0-test11/net/ipv4/netfilter/Makefile 2003-12-10 23:24:46.646649464 +0100 @@ -19,37 +19,91 @@ # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o +# talk protocol support +obj-$(CONFIG_IP_NF_TALK) += ip_conntrack_talk.o +obj-$(CONFIG_IP_NF_NAT_TALK) += ip_nat_talk.o + + +# H.323 support +obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o +obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o + + # connection tracking helpers +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o + +# rtsp protocol support +obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o +obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o + +obj-$(CONFIG_IP_NF_QUAKE3) += ip_conntrack_quake3.o +obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o +obj-$(CONFIG_IP_NF_RSH) += ip_conntrack_rsh.o + +obj-$(CONFIG_IP_NF_EGG) += ip_conntrack_egg.o + obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o # NAT helpers +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o +obj-$(CONFIG_IP_NF_NAT_CUSEEME) += ip_nat_cuseeme.o obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o +obj-$(CONFIG_IP_NF_NAT_QUAKE3) += ip_nat_quake3.o +obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o -# the three instances of ip_tables +# the four instances of ip_tables obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o +obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o # matches +obj-$(CONFIG_IP_NF_MATCH_RPC) += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o ipt_rpc.o + +obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o +obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o +obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o +obj-$(CONFIG_IP_NF_POOL) += ipt_pool.o ipt_POOL.o ip_pool.o obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o + +obj-$(CONFIG_IP_NF_MATCH_MPORT) += ipt_mport.o + obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o +obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o + +obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o + + +obj-$(CONFIG_IP_NF_MATCH_RANDOM) += ipt_random.o + +obj-$(CONFIG_IP_NF_MATCH_PSD) += ipt_psd.o + +obj-$(CONFIG_IP_NF_MATCH_OSF) += ipt_osf.o + + +obj-$(CONFIG_IP_NF_MATCH_NTH) += ipt_nth.o + +obj-$(CONFIG_IP_NF_MATCH_IPV4OPTIONS) += ipt_ipv4options.o + + +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o @@ -59,10 +113,18 @@ obj-$(CONFIG_IP_NF_MATCH_LENGTH) += ipt_length.o +obj-$(CONFIG_IP_NF_MATCH_U32) += ipt_u32.o + + obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o +obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o +obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o +obj-$(CONFIG_IP_NF_MATCH_CONNLIMIT) += ipt_connlimit.o obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o +obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o +obj-$(CONFIG_IP_NF_MATCH_REALM) += ipt_realm.o obj-$(CONFIG_IP_NF_MATCH_PHYSDEV) += ipt_physdev.o @@ -72,15 +134,28 @@ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o +obj-$(CONFIG_IP_NF_TARGET_IPMARK) += ipt_IPMARK.o +obj-$(CONFIG_IP_NF_TARGET_TARPIT) += ipt_TARPIT.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o +obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o +obj-$(CONFIG_IP_NF_TARGET_XOR) += ipt_XOR.o +obj-$(CONFIG_IP_NF_TARGET_TCPLAG) += ipt_TCPLAG.o +obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o +obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o + +obj-$(CONFIG_IP_NF_TARGET_NETLINK) += ipt_NETLINK.o + +obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o +obj-$(CONFIG_IP_NF_TARGET_NOTRACK) += ipt_NOTRACK.o +obj-$(CONFIG_IP_NF_TARGET_TRACE) += ipt_TRACE.o # generic ARP tables obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6table_filter.c linux-2.6.0-test11/net/ipv6/netfilter/ip6table_filter.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6table_filter.c 2003-11-26 21:42:56.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6table_filter.c 2003-12-10 23:13:24.668325928 +0100 @@ -52,7 +52,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* FORWARD */ @@ -60,7 +60,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_OUT */ @@ -68,7 +68,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } } }, @@ -77,7 +77,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_error), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, { } }, "ERROR" diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6table_mangle.c linux-2.6.0-test11/net/ipv6/netfilter/ip6table_mangle.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6table_mangle.c 2003-11-26 21:43:36.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6table_mangle.c 2003-12-10 23:13:24.668325928 +0100 @@ -66,7 +66,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_IN */ @@ -74,7 +74,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* FORWARD */ @@ -82,7 +82,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* LOCAL_OUT */ @@ -90,7 +90,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } }, /* POST_ROUTING */ @@ -98,7 +98,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_standard), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, -NF_ACCEPT - 1 } } }, @@ -107,7 +107,7 @@ 0, sizeof(struct ip6t_entry), sizeof(struct ip6t_error), - 0, { 0, 0 }, { } }, + 0, NULL, 0, { 0, 0 }, { } }, { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, { } }, "ERROR" diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6table_raw.c linux-2.6.0-test11/net/ipv6/netfilter/ip6table_raw.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6table_raw.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6table_raw.c 2003-12-10 23:13:24.668325928 +0100 @@ -0,0 +1,158 @@ +/* + * IPv6 raw table, a port of the IPv4 raw table to IPv6 + * + * Copyright (C) 2003 Jozsef Kadlecsik + */ +#include +#include + +#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT)) + +#if 0 +#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args) +#else +#define DEBUGP(x, args...) +#endif + +/* Standard entry. */ +struct ip6t_standard +{ + struct ip6t_entry entry; + struct ip6t_standard_target target; +}; + +struct ip6t_error_target +{ + struct ip6t_entry_target target; + char errorname[IP6T_FUNCTION_MAXNAMELEN]; +}; + +struct ip6t_error +{ + struct ip6t_entry entry; + struct ip6t_error_target target; +}; + +static struct +{ + struct ip6t_replace repl; + struct ip6t_standard entries[2]; + struct ip6t_error term; +} initial_table __initdata += { { "raw", RAW_VALID_HOOKS, 3, + sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error), + { [NF_IP6_PRE_ROUTING] 0, + [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) }, + { [NF_IP6_PRE_ROUTING] 0, + [NF_IP6_LOCAL_OUT] sizeof(struct ip6t_standard) }, + 0, NULL, { } }, + { + /* PRE_ROUTING */ + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ip6t_entry), + sizeof(struct ip6t_standard), + 0, NULL, 0, { 0, 0 }, { } }, + { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } }, + /* LOCAL_OUT */ + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ip6t_entry), + sizeof(struct ip6t_standard), + 0, NULL, 0, { 0, 0 }, { } }, + { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } }, + -NF_ACCEPT - 1 } }, + }, + /* ERROR */ + { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 }, + 0, + sizeof(struct ip6t_entry), + sizeof(struct ip6t_error), + 0, NULL, 0, { 0, 0 }, { } }, + { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } }, + { } }, + "ERROR" + } + } +}; + +static struct ip6t_table packet_raw = { + .name = "raw", + .table = &initial_table.repl, + .valid_hooks = RAW_VALID_HOOKS, + .lock = RW_LOCK_UNLOCKED, + .me = THIS_MODULE +}; + +/* The work comes in here from netfilter.c. */ +static unsigned int +ip6t_hook(unsigned int hook, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ip6t_do_table(pskb, hook, in, out, &packet_raw, NULL); +} + +static struct nf_hook_ops ip6t_ops[] = { + { /* PRE_ROUTING */ + .hook = ip6t_hook, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_PRE_ROUTING, + .priority = NF_IP6_PRI_FIRST, + }, + { /* LOCAL_OUT */ + .hook = ip6t_hook, + .owner = THIS_MODULE, + .pf = PF_INET6, + .hooknum = NF_IP6_LOCAL_OUT, + .priority = NF_IP6_PRI_FIRST, + }, +}; + +static int __init init(void) +{ + int ret; + + /* Register table */ + ret = ip6t_register_table(&packet_raw); + if (ret < 0) + return ret; + + /* Register hooks */ + ret = nf_register_hook(&ip6t_ops[0]); + if (ret < 0) + goto cleanup_table; + + ret = nf_register_hook(&ip6t_ops[1]); + if (ret < 0) + goto cleanup_hook0; + + return ret; + + cleanup_hook0: + nf_unregister_hook(&ip6t_ops[0]); + cleanup_table: + ip6t_unregister_table(&packet_raw); + + return ret; +} + +static void __exit fini(void) +{ + unsigned int i; + + for (i = 0; i < sizeof(ip6t_ops)/sizeof(struct nf_hook_ops); i++) + nf_unregister_hook(&ip6t_ops[i]); + + ip6t_unregister_table(&packet_raw); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_DESCRIPTION("IPv6 raw table"); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6_tables.c linux-2.6.0-test11/net/ipv6/netfilter/ip6_tables.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6_tables.c 2003-11-26 21:45:30.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6_tables.c 2003-12-10 23:13:24.667326080 +0100 @@ -12,6 +12,7 @@ */ #include #include +#include #include #include #include @@ -24,8 +25,17 @@ #include #include +#include #include +static const char *hook6names[] = { + [NF_IP6_PRE_ROUTING] "PREROUTING", + [NF_IP6_LOCAL_IN] "INPUT", + [NF_IP6_FORWARD] "FORWARD", + [NF_IP6_LOCAL_OUT] "OUTPUT", + [NF_IP6_POST_ROUTING] "POSTROUTING", +}; + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); MODULE_DESCRIPTION("IPv6 packet filter"); @@ -403,6 +413,12 @@ t = ip6t_get_target(e); IP_NF_ASSERT(t->u.kernel.target); + + /* The packet traced and the rule isn't an unconditional return/END. */ + if (((*pskb)->nfcache & NFC_TRACE) && e->rulenum) { + nf_log_packet(AF_INET6, hook, *pskb, in, out, "TRACE: %s/%s/%u ", + table->name, e->chainname, e->rulenum); + } /* Standard target? */ if (!t->u.kernel.target->target) { int v; @@ -556,6 +572,29 @@ return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); } +static inline int +find_error_target(struct ip6t_entry *s, + struct ip6t_entry *e, + char **chainname) +{ + struct ip6t_entry_target *t; + static struct ip6t_entry *found = NULL; + + if (s == e) { + if (!found) + return 0; + t = ip6t_get_target(found); + if (strcmp(t->u.user.name, + IP6T_ERROR_TARGET) == 0) { + *chainname = t->data; + return 1; + } + } else + found = s; + + return 0; +} + /* All zeroes == unconditional rule. */ static inline int unconditional(const struct ip6t_ip6 *ipv6) @@ -575,6 +614,8 @@ mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks) { unsigned int hook; + char *chainname = NULL; + u_int32_t rulenum; /* No recursion; use packet counter to save back ptrs (reset to 0 as we leave), and comefrom to save source hook bitmask */ @@ -588,6 +629,8 @@ /* Set initial back pointer. */ e->counters.pcnt = pos; + rulenum = 1; + chainname = (char *) hook6names[hook]; for (;;) { struct ip6t_standard_target *t @@ -600,6 +643,8 @@ } e->comefrom |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS)); + e->rulenum = rulenum++; + e->chainname = chainname; /* Unconditional return/END. */ if (e->target_offset == sizeof(struct ip6t_entry) @@ -609,6 +654,10 @@ && unconditional(&e->ipv6)) { unsigned int oldpos, size; + /* Set unconditional rulenum to zero. */ + e->rulenum = 0; + e->counters.bcnt = 0; + /* Return: backtrack through the last big jump. */ do { @@ -634,6 +683,11 @@ (newinfo->entries + pos); } while (oldpos == pos + e->next_offset); + /* Restore chainname, rulenum. */ + chainname = e->chainname; + rulenum = e->counters.bcnt; + e->counters.bcnt = 0; + /* Move along one */ size = e->next_offset; e = (struct ip6t_entry *) @@ -649,6 +703,17 @@ /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); + e->counters.bcnt = rulenum++; + rulenum = 1; + e = (struct ip6t_entry *) + (newinfo->entries + newpos); + if (IP6T_ENTRY_ITERATE(newinfo->entries, + newinfo->size, + find_error_target, + e, &chainname) == 0) { + printk("ip6_tables: table screwed up!\n"); + return 0; + } } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_condition.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_condition.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_condition.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_condition.c 2003-12-10 23:13:52.256131944 +0100 @@ -0,0 +1,254 @@ +/*-------------------------------------------*\ +| Netfilter Condition Module for IPv6 | +| | +| Description: This module allows firewall | +| rules to match using condition variables | +| stored in /proc files. | +| | +| Author: Stephane Ouellette 2003-02-10 | +| | +| | +| This software is distributed under the | +| terms of the GNU GPL. | +\*-------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include + + +#ifndef CONFIG_PROC_FS +#error "Proc file system support is required for this module" +#endif + + +MODULE_AUTHOR("Stephane Ouellette "); +MODULE_DESCRIPTION("Allows rules to match against condition variables"); +MODULE_LICENSE("GPL"); + + +struct condition_variable { + struct condition_variable *next; + struct proc_dir_entry *status_proc; + atomic_t refcount; + int enabled; /* TRUE == 1, FALSE == 0 */ +}; + + +static rwlock_t list_lock; +static struct condition_variable *head = NULL; +static struct proc_dir_entry *proc_net_condition = NULL; + + +static int +ipt_condition_read_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (offset == 0) { + *start = buffer; + buffer[0] = (var->enabled) ? '1' : '0'; + buffer[1] = '\n'; + return 2; + } + + *eof = 1; + return 0; +} + + +static int +ipt_condition_write_info(struct file *file, const char *buffer, + unsigned long length, void *data) +{ + struct condition_variable *var = + (struct condition_variable *) data; + + if (length) { + /* Match only on the first character */ + switch (buffer[0]) { + case '0': + var->enabled = 0; + break; + case '1': + var->enabled = 1; + } + } + + return (int) length; +} + + +static int +match(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const void *matchinfo, int offset, + const void *hdr, u_int16_t datalen, int *hotdrop) +{ + const struct condition6_info *info = + (const struct condition6_info *) matchinfo; + struct condition_variable *var; + int condition_status = 0; + + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + condition_status = var->enabled; + break; + } + } + + read_unlock(&list_lock); + + return condition_status ^ info->invert; +} + + + +static int +checkentry(const char *tablename, const struct ip6t_ip6 *ip, + void *matchinfo, unsigned int matchsize, unsigned int hook_mask) +{ + struct condition6_info *info = + (struct condition6_info *) matchinfo; + struct condition_variable *var, *newvar; + + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) + return 0; + + /* The first step is to check if the condition variable already exists. */ + /* Here, a read lock is sufficient because we won't change the list */ + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + + /* At this point, we need to allocate a new condition variable */ + newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL); + + if (!newvar) + return -ENOMEM; + + /* Create the condition variable's proc file entry */ + newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition); + + if (!newvar->status_proc) { + /* + * There are two possibilities: + * 1- Another condition variable with the same name has been created, which is valid. + * 2- There was a memory allocation error. + */ + kfree(newvar); + read_lock(&list_lock); + + for (var = head; var; var = var->next) { + if (strcmp(info->name, var->status_proc->name) == 0) { + atomic_inc(&var->refcount); + read_unlock(&list_lock); + return 1; + } + } + + read_unlock(&list_lock); + return -ENOMEM; + } + + atomic_set(&newvar->refcount, 1); + newvar->enabled = 0; + newvar->status_proc->owner = THIS_MODULE; + newvar->status_proc->data = newvar; + wmb(); + newvar->status_proc->read_proc = ipt_condition_read_info; + newvar->status_proc->write_proc = ipt_condition_write_info; + + write_lock(&list_lock); + + newvar->next = head; + head = newvar; + + write_unlock(&list_lock); + + return 1; +} + + +static void +destroy(void *matchinfo, unsigned int matchsize) +{ + struct condition6_info *info = + (struct condition6_info *) matchinfo; + struct condition_variable *var, *prev = NULL; + + if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info))) + return; + + write_lock(&list_lock); + + for (var = head; var && strcmp(info->name, var->status_proc->name); + prev = var, var = var->next); + + if (var && atomic_dec_and_test(&var->refcount)) { + if (prev) + prev->next = var->next; + else + head = var->next; + + write_unlock(&list_lock); + remove_proc_entry(var->status_proc->name, proc_net_condition); + kfree(var); + } else + write_unlock(&list_lock); +} + + +static struct ip6t_match condition_match = { + .name = "condition", + .match = &match, + .checkentry = &checkentry, + .destroy = &destroy, + .me = THIS_MODULE +}; + + +static int __init +init(void) +{ + int errorcode; + + rwlock_init(&list_lock); + proc_net_condition = proc_mkdir("ip6t_condition", proc_net); + + if (proc_net_condition) { + errorcode = ipt_register_match(&condition_match); + + if (errorcode) + remove_proc_entry("ip6t_condition", proc_net); + } else + errorcode = -EACCES; + + return errorcode; +} + + +static void __exit +fini(void) +{ + ipt_unregister_match(&condition_match); + remove_proc_entry("ip6t_condition", proc_net); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_fuzzy.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_fuzzy.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_fuzzy.c 2003-12-10 23:13:28.963672936 +0100 @@ -0,0 +1,189 @@ +/* + * This module implements a simple TSK FLC + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims + * to limit , in an adaptive and flexible way , the packet rate crossing + * a given stream . It serves as an initial and very simple (but effective) + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks. + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior" + * into our code in a precise , adaptive and efficient manner. + * The goal is very similar to that of "limit" match , but using techniques of + * Fuzzy Control , that allow us to shape the transfer functions precisely , + * avoiding over and undershoots - and stuff like that . + * + * + * 2002-08-10 Hime Aguiar e Oliveira Jr. : Initial version. + * 2002-08-17 : Changed to eliminate floating point operations . + * 2002-08-23 : Coding style changes . + * 2003-04-08 Maciej Soltysiak : IPv6 Port + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH + Expressed in percentage +*/ + +#define PAR_LOW 1/100 +#define PAR_HIGH 1 + +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED; + +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior "); +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module"); +MODULE_LICENSE("GPL"); + +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi) +{ + if (tx >= maxi) return 100; + + if (tx <= mini) return 0; + + return ((100 * (tx-mini)) / (maxi-mini)); +} + +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi) +{ + if (tx <= mini) return 100; + + if (tx >= maxi) return 0; + + return ((100 * (maxi - tx)) / (maxi - mini)); + +} + +static int +ip6t_fuzzy_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* From userspace */ + + struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo; + + u_int8_t random_number; + unsigned long amount; + u_int8_t howhigh, howlow; + + + spin_lock_bh(&fuzzy_lock); /* Rise the lock */ + + info->bytes_total += pskb->len; + info->packets_total++; + + info->present_time = jiffies; + + if (info->present_time >= info->previous_time) + amount = info->present_time - info->previous_time; + else { + /* There was a transition : I choose to re-sample + and keep the old acceptance rate... + */ + + amount = 0; + info->previous_time = info->present_time; + info->bytes_total = info->packets_total = 0; + }; + + if ( amount > HZ/10) {/* More than 100 ms elapsed ... */ + + info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \ + / amount); + + info->previous_time = info->present_time; + info->bytes_total = info->packets_total = 0; + + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate); + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate); + + info->acceptance_rate = (u_int8_t) \ + (howhigh * PAR_LOW + PAR_HIGH * howlow); + + /* In fact, the above defuzzification would require a denominator + * proportional to (howhigh+howlow) but, in this particular case, + * that expression is constant. + * An imediate consequence is that it is not necessary to call + * both mf_high and mf_low - but to keep things understandable, + * I did so. + */ + + } + + spin_unlock_bh(&fuzzy_lock); /* Release the lock */ + + + if (info->acceptance_rate < 100) + { + get_random_bytes((void *)(&random_number), 1); + + /* If within the acceptance , it can pass => don't match */ + if (random_number <= (255 * info->acceptance_rate) / 100) + return 0; + else + return 1; /* It can't pass (It matches) */ + }; + + return 0; /* acceptance_rate == 100 % => Everything passes ... */ + +} + +static int +ip6t_fuzzy_checkentry(const char *tablename, + const struct ip6t_ip6 *ip, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + + const struct ip6t_fuzzy_info *info = matchinfo; + + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) { + printk("ip6t_fuzzy: matchsize %u != %u\n", matchsize, + IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))); + return 0; + } + + if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE) + || (info->minimum_rate >= info->maximum_rate)) { + printk("ip6t_fuzzy: BAD limits , please verify !!!\n"); + return 0; + } + + return 1; +} + +static struct ip6t_match ip6t_fuzzy_reg = { + {NULL, NULL}, + "fuzzy", + ip6t_fuzzy_match, + ip6t_fuzzy_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ip6t_register_match(&ip6t_fuzzy_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_match(&ip6t_fuzzy_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_HL.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_HL.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_HL.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_HL.c 2003-12-10 23:13:31.108346896 +0100 @@ -0,0 +1,105 @@ +/* + * Hop Limit modification target for ip6tables + * Maciej Soltysiak + * Based on HW's TTL module + * + * This software is distributed under the terms of GNU GPL + */ + +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Maciej Soltysiak "); +MODULE_DESCRIPTION("IP tables Hop Limit modification module"); +MODULE_LICENSE("GPL"); + +static unsigned int ip6t_hl_target(struct sk_buff **pskb, unsigned int hooknum, + const struct net_device *in, const struct net_device *out, + const void *targinfo, void *userinfo) +{ + struct ipv6hdr *ip6h = (*pskb)->nh.ipv6h; + const struct ip6t_HL_info *info = targinfo; + u_int16_t diffs[2]; + int new_hl; + + switch (info->mode) { + case IP6T_HL_SET: + new_hl = info->hop_limit; + break; + case IP6T_HL_INC: + new_hl = ip6h->hop_limit + info->hop_limit; + if (new_hl > 255) + new_hl = 255; + break; + case IP6T_HL_DEC: + new_hl = ip6h->hop_limit + info->hop_limit; + if (new_hl < 0) + new_hl = 0; + break; + default: + new_hl = ip6h->hop_limit; + break; + } + + if (new_hl != ip6h->hop_limit) { + diffs[0] = htons(((unsigned)ip6h->hop_limit) << 8) ^ 0xFFFF; + ip6h->hop_limit = new_hl; + diffs[1] = htons(((unsigned)ip6h->hop_limit) << 8); + } + + return IP6T_CONTINUE; +} + +static int ip6t_hl_checkentry(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + struct ip6t_HL_info *info = targinfo; + + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_HL_info))) { + printk(KERN_WARNING "HL: targinfosize %u != %Zu\n", + targinfosize, + IP6T_ALIGN(sizeof(struct ip6t_HL_info))); + return 0; + } + + if (strcmp(tablename, "mangle")) { + printk(KERN_WARNING "HL: can only be called from \"mangle\" table, not \"%s\"\n", tablename); + return 0; + } + + if (info->mode > IP6T_HL_MAXMODE) { + printk(KERN_WARNING "HL: invalid or unknown Mode %u\n", + info->mode); + return 0; + } + + if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) { + printk(KERN_WARNING "HL: increment/decrement doesn't make sense with value 0\n"); + return 0; + } + + return 1; +} + +static struct ip6t_target ip6t_HL = { { NULL, NULL }, "HL", + ip6t_hl_target, ip6t_hl_checkentry, NULL, THIS_MODULE }; + +static int __init init(void) +{ + return ip6t_register_target(&ip6t_HL); +} + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_HL); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_LOG.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_LOG.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_LOG.c 2003-11-26 21:43:30.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_LOG.c 2003-12-10 23:13:22.347678720 +0100 @@ -3,18 +3,24 @@ */ #include #include +#include #include #include #include #include #include #include +#include #include MODULE_AUTHOR("Jan Rekorajski "); MODULE_DESCRIPTION("IP6 tables LOG target module"); MODULE_LICENSE("GPL"); +static unsigned int nflog = 1; +MODULE_PARM(nflog, "i"); +MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); + struct in_device; #include #include @@ -256,40 +262,38 @@ } } -static unsigned int -ip6t_log_target(struct sk_buff **pskb, - unsigned int hooknum, - const struct net_device *in, - const struct net_device *out, - const void *targinfo, - void *userinfo) +static void +ip6t_log_packet(unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct ip6t_log_info *loginfo, + const char *level_string, + const char *prefix) { - struct ipv6hdr *ipv6h = (*pskb)->nh.ipv6h; - const struct ip6t_log_info *loginfo = targinfo; - char level_string[4] = "< >"; + struct ipv6hdr *ipv6h = skb->nh.ipv6h; - level_string[1] = '0' + (loginfo->level % 8); spin_lock_bh(&log_lock); printk(level_string); printk("%sIN=%s OUT=%s ", - loginfo->prefix, + prefix == NULL ? loginfo->prefix : prefix, in ? in->name : "", out ? out->name : ""); if (in && !out) { /* MAC logging for input chain only. */ printk("MAC="); - if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) { - if ((*pskb)->dev->type != ARPHRD_SIT){ + if (skb->dev && skb->dev->hard_header_len && skb->mac.raw != (void*)ipv6h) { + if (skb->dev->type != ARPHRD_SIT){ int i; - unsigned char *p = (*pskb)->mac.raw; - for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++) + unsigned char *p = skb->mac.raw; + for (i = 0; i < skb->dev->hard_header_len; i++,p++) printk("%02x%c", *p, - i==(*pskb)->dev->hard_header_len - 1 + i==skb->dev->hard_header_len - 1 ? ' ':':'); } else { int i; - unsigned char *p = (*pskb)->mac.raw; - if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){ + unsigned char *p = skb->mac.raw; + if ( p - (ETH_ALEN*2+2) > skb->head ){ p -= (ETH_ALEN+2); for (i = 0; i < (ETH_ALEN); i++,p++) printk("%02x%s", *p, @@ -300,10 +304,10 @@ i == ETH_ALEN-1 ? ' ' : ':'); } - if (((*pskb)->dev->addr_len == 4) && - (*pskb)->dev->hard_header_len > 20){ + if ((skb->dev->addr_len == 4) && + skb->dev->hard_header_len > 20){ printk("TUNNEL="); - p = (*pskb)->mac.raw + 12; + p = skb->mac.raw + 12; for (i = 0; i < 4; i++,p++) printk("%3d%s", *p, i == 3 ? "->" : "."); @@ -319,10 +323,41 @@ dump_packet(loginfo, ipv6h, 1); printk("\n"); spin_unlock_bh(&log_lock); +} + +static unsigned int +ip6t_log_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ip6t_log_info *loginfo = targinfo; + char level_string[4] = "< >"; + + level_string[1] = '0' + (loginfo->level % 8); + ip6t_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL); return IP6T_CONTINUE; } +static void +ip6t_logfn(unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const char *prefix) +{ + struct ip6t_log_info loginfo = { + .level = 0, + .logflags = IP6T_LOG_MASK, + .prefix = "" + }; + + ip6t_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix); +} + static int ip6t_log_checkentry(const char *tablename, const struct ip6t_entry *e, void *targinfo, @@ -359,12 +394,17 @@ { if (ip6t_register_target(&ip6t_log_reg)) return -EINVAL; + if (nflog) + nf_log_register(PF_INET6, &ip6t_logfn); return 0; } static void __exit fini(void) { + if (nflog) + nf_log_register(PF_INET6, &ip6t_logfn); + ip6t_unregister_target(&ip6t_log_reg); } diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_nth.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_nth.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_nth.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_nth.c 2003-12-10 23:13:36.623508464 +0100 @@ -0,0 +1,173 @@ +/* + This is a module which is used for match support for every Nth packet + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2001-07-18 Fabrice MARIE : initial implementation. + 2001-09-20 Richard Wagner (rwagner@cloudnet.com) + * added support for multiple counters + * added support for matching on individual packets + in the counter cycle + 2003-04-30 Maciej Soltysiak : IPv6 Port + +*/ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +/* + * State information. + */ +struct state { + spinlock_t lock; + u_int16_t number; +}; + +static struct state states[IP6T_NTH_NUM_COUNTERS]; + +static int +ip6t_nth_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* Parameters from userspace */ + const struct ip6t_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1); + return 0; + }; + + spin_lock(&states[counter].lock); + + /* Are we matching every nth packet?*/ + if (info->packet == 0xFF) + { + /* We're matching every nth packet and only every nth packet*/ + /* Do we match or invert match? */ + if (info->not == 0) + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto match; + } + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto dontmatch; + } + else + { + if (states[counter].number == 0) + { + ++states[counter].number; + goto dontmatch; + } + if (states[counter].number >= info->every) + states[counter].number = 0; + else + ++states[counter].number; + goto match; + } + } + else + { + /* We're using the --packet, so there must be a rule for every value */ + if (states[counter].number == info->packet) + { + /* only increment the counter when a match happens */ + if (states[counter].number >= info->every) + states[counter].number = 0; /* reset the counter */ + else + ++states[counter].number; + goto match; + } + else + goto dontmatch; + } + + dontmatch: + /* don't match */ + spin_unlock(&states[counter].lock); + return 0; + + match: + spin_unlock(&states[counter].lock); + return 1; +} + +static int +ip6t_nth_checkentry(const char *tablename, + const struct ip6t_ip6 *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Parameters from userspace */ + const struct ip6t_nth_info *info = matchinfo; + unsigned counter = info->counter; + if((counter < 0) || (counter >= IP6T_NTH_NUM_COUNTERS)) + { + printk(KERN_WARNING "nth: invalid counter %u. counter between 0 and %u\n", counter, IP6T_NTH_NUM_COUNTERS-1); + return 0; + }; + + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_nth_info))) { + printk("nth: matchsize %u != %u\n", matchsize, + IP6T_ALIGN(sizeof(struct ip6t_nth_info))); + return 0; + } + + states[counter].number = info->startat; + + return 1; +} + +static struct ip6t_match ip6t_nth_reg = { + {NULL, NULL}, + "nth", + ip6t_nth_match, + ip6t_nth_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + unsigned counter; + memset(&states, 0, sizeof(states)); + if (ip6t_register_match(&ip6t_nth_reg)) + return -EINVAL; + + for(counter = 0; counter < IP6T_NTH_NUM_COUNTERS; counter++) + { + spin_lock_init(&(states[counter].lock)); + }; + + printk("ip6t_nth match loaded\n"); + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_match(&ip6t_nth_reg); + printk("ip6t_nth match unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_owner.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_owner.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_owner.c 2003-11-26 21:45:19.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_owner.c 2003-12-10 23:14:05.029190144 +0100 @@ -16,6 +16,38 @@ MODULE_LICENSE("GPL"); static int +match_comm(const struct sk_buff *skb, const char *comm) +{ + struct task_struct *p; + struct files_struct *files; + int i; + + read_lock(&tasklist_lock); + for_each_task(p) { + if(strncmp(p->comm, comm, sizeof(p->comm))) + continue; + + task_lock(p); + files = p->files; + if(files) { + read_lock(&files->file_lock); + for (i=0; i < files->max_fds; i++) { + if (fcheck_files(files, i) == skb->sk->socket->file) { + read_unlock(&files->file_lock); + task_unlock(p); + read_unlock(&tasklist_lock); + return 1; + } + } + read_unlock(&files->file_lock); + } + task_unlock(p); + } + read_unlock(&tasklist_lock); + return 0; +} + +static int match_pid(const struct sk_buff *skb, pid_t pid) { struct task_struct *p; @@ -120,6 +152,12 @@ return 0; } + if(info->match & IP6T_OWNER_COMM) { + if (!match_comm(skb, info->comm) ^ + !!(info->invert & IP6T_OWNER_COMM)) + return 0; + } + return 1; } diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_random.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_random.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_random.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_random.c 2003-12-10 23:13:43.304492800 +0100 @@ -0,0 +1,97 @@ +/* + This is a module which is used for a "random" match support. + This file is distributed under the terms of the GNU General Public + License (GPL). Copies of the GPL can be obtained from: + ftp://prep.ai.mit.edu/pub/gnu/GPL + + 2001-10-14 Fabrice MARIE : initial implementation. + 2003-04-30 Maciej Soltysiak : IPv6 Port +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static int +ip6t_rand_match(const struct sk_buff *pskb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, + int offset, + const void *hdr, + u_int16_t datalen, + int *hotdrop) +{ + /* Parameters from userspace */ + const struct ip6t_rand_info *info = matchinfo; + u_int8_t random_number; + + /* get 1 random number from the kernel random number generation routine */ + get_random_bytes((void *)(&random_number), 1); + + /* Do we match ? */ + if (random_number <= info->average) + return 1; + else + return 0; +} + +static int +ip6t_rand_checkentry(const char *tablename, + const struct ip6t_ip6 *e, + void *matchinfo, + unsigned int matchsize, + unsigned int hook_mask) +{ + /* Parameters from userspace */ + const struct ip6t_rand_info *info = matchinfo; + + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_rand_info))) { + printk("ip6t_random: matchsize %u != %u\n", matchsize, + IP6T_ALIGN(sizeof(struct ip6t_rand_info))); + return 0; + } + + /* must be 1 <= average % <= 99 */ + /* 1 x 2.55 = 2 */ + /* 99 x 2.55 = 252 */ + if ((info->average < 2) || (info->average > 252)) { + printk("ip6t_random: invalid average %u\n", info->average); + return 0; + } + + return 1; +} + +static struct ip6t_match ip6t_rand_reg = { + {NULL, NULL}, + "random", + ip6t_rand_match, + ip6t_rand_checkentry, + NULL, + THIS_MODULE }; + +static int __init init(void) +{ + if (ip6t_register_match(&ip6t_rand_reg)) + return -EINVAL; + + printk("ip6t_random match loaded\n"); + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_match(&ip6t_rand_reg); + printk("ip6t_random match unloaded\n"); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_REJECT.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_REJECT.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_REJECT.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_REJECT.c 2003-12-10 23:13:46.680979496 +0100 @@ -0,0 +1,274 @@ +/* + * This is a module which is used for rejecting packets. + * Added support for customized reject packets (Jozsef Kadlecsik). + * Sun 12 Nov 2000 + * Port to IPv6 / ip6tables (Harald Welte ) + */ +#include +#include +#include +#include +#include +#include +#include + +#if 1 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#if 0 +/* Send RST reply */ +static void send_reset(struct sk_buff *oldskb) +{ + struct sk_buff *nskb; + struct tcphdr *otcph, *tcph; + struct rtable *rt; + unsigned int otcplen; + int needs_ack; + + /* IP header checks: fragment, too short. */ + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET) + || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr)) + return; + + otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl); + otcplen = oldskb->len - oldskb->nh.iph->ihl*4; + + /* No RST for RST. */ + if (otcph->rst) + return; + + /* Check checksum. */ + if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr, + oldskb->nh.iph->daddr, + csum_partial((char *)otcph, otcplen, 0)) != 0) + return; + + /* Copy skb (even if skb is about to be dropped, we can't just + clone it because there may be other things, such as tcpdump, + interested in it) */ + nskb = skb_copy(oldskb, GFP_ATOMIC); + if (!nskb) + return; + + /* This packet will not be the same as the other: clear nf fields */ + nf_conntrack_put(nskb->nfct); + nskb->nfct = NULL; + nskb->nfcache = 0; +#ifdef CONFIG_NETFILTER_DEBUG + nskb->nf_debug = 0; +#endif + + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); + + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); + tcph->source = xchg(&tcph->dest, tcph->source); + + /* Truncate to length (no data) */ + tcph->doff = sizeof(struct tcphdr)/4; + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); + nskb->nh.iph->tot_len = htons(nskb->len); + + if (tcph->ack) { + needs_ack = 0; + tcph->seq = otcph->ack_seq; + tcph->ack_seq = 0; + } else { + needs_ack = 1; + tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin + + otcplen - (otcph->doff<<2)); + tcph->seq = 0; + } + + /* Reset flags */ + ((u_int8_t *)tcph)[13] = 0; + tcph->rst = 1; + tcph->ack = needs_ack; + + tcph->window = 0; + tcph->urg_ptr = 0; + + /* Adjust TCP checksum */ + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), + nskb->nh.iph->saddr, + nskb->nh.iph->daddr, + csum_partial((char *)tcph, + sizeof(struct tcphdr), 0)); + + /* Adjust IP TTL, DF */ + nskb->nh.iph->ttl = MAXTTL; + /* Set DF, id = 0 */ + nskb->nh.iph->frag_off = htons(IP_DF); + nskb->nh.iph->id = 0; + + /* Adjust IP checksum */ + nskb->nh.iph->check = 0; + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, + nskb->nh.iph->ihl); + + /* Routing */ + if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr, + RT_TOS(nskb->nh.iph->tos) | RTO_CONN, + 0) != 0) + goto free_nskb; + + dst_release(nskb->dst); + nskb->dst = &rt->u.dst; + + /* "Never happens" */ + if (nskb->len > nskb->dst->pmtu) + goto free_nskb; + + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, + ip_finish_output); + return; + + free_nskb: + kfree_skb(nskb); +} +#endif + +static unsigned int reject6_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ip6t_reject_info *reject = targinfo; + + /* WARNING: This code causes reentry within ip6tables. + This means that the ip6tables jump stack is now crap. We + must return an absolute verdict. --RR */ + DEBUGP("REJECTv6: calling icmpv6_send\n"); + switch (reject->with) { + case IP6T_ICMP6_NO_ROUTE: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, out); + break; + case IP6T_ICMP6_ADM_PROHIBITED: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, out); + break; + case IP6T_ICMP6_NOT_NEIGHBOUR: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_NOT_NEIGHBOUR, 0, out); + break; + case IP6T_ICMP6_ADDR_UNREACH: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, out); + break; + case IP6T_ICMP6_PORT_UNREACH: + icmpv6_send(*pskb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, out); + break; +#if 0 + case IPT_ICMP_ECHOREPLY: { + struct icmp6hdr *icmph = (struct icmphdr *) + ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl); + unsigned int datalen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; + + /* Not non-head frags, or truncated */ + if (((ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET) == 0) + && datalen >= 4) { + /* Usually I don't like cut & pasting code, + but dammit, my party is starting in 45 + mins! --RR */ + struct icmp_bxm icmp_param; + + icmp_param.icmph=*icmph; + icmp_param.icmph.type=ICMP_ECHOREPLY; + icmp_param.data_ptr=(icmph+1); + icmp_param.data_len=datalen; + icmp_reply(&icmp_param, *pskb); + } + } + break; + case IPT_TCP_RESET: + send_reset(*pskb); + break; +#endif + default: + printk(KERN_WARNING "REJECTv6: case %u not handled yet\n", reject->with); + break; + } + + return NF_DROP; +} + +static inline int find_ping_match(const struct ip6t_entry_match *m) +{ + const struct ip6t_icmp *icmpinfo = (const struct ip6t_icmp *)m->data; + + if (strcmp(m->u.kernel.match->name, "icmp6") == 0 + && icmpinfo->type == ICMPV6_ECHO_REQUEST + && !(icmpinfo->invflags & IP6T_ICMP_INV)) + return 1; + + return 0; +} + +static int check(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + const struct ip6t_reject_info *rejinfo = targinfo; + + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_reject_info))) { + DEBUGP("REJECTv6: targinfosize %u != 0\n", targinfosize); + return 0; + } + + /* Only allow these for packet filtering. */ + if (strcmp(tablename, "filter") != 0) { + DEBUGP("REJECTv6: bad table `%s'.\n", tablename); + return 0; + } + if ((hook_mask & ~((1 << NF_IP6_LOCAL_IN) + | (1 << NF_IP6_FORWARD) + | (1 << NF_IP6_LOCAL_OUT))) != 0) { + DEBUGP("REJECTv6: bad hook mask %X\n", hook_mask); + return 0; + } + + if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) { + /* Must specify that it's an ICMP ping packet. */ + if (e->ipv6.proto != IPPROTO_ICMPV6 + || (e->ipv6.invflags & IP6T_INV_PROTO)) { + DEBUGP("REJECTv6: ECHOREPLY illegal for non-icmp\n"); + return 0; + } + /* Must contain ICMP match. */ + if (IP6T_MATCH_ITERATE(e, find_ping_match) == 0) { + DEBUGP("REJECTv6: ECHOREPLY illegal for non-ping\n"); + return 0; + } + } else if (rejinfo->with == IP6T_TCP_RESET) { + /* Must specify that it's a TCP packet */ + if (e->ipv6.proto != IPPROTO_TCP + || (e->ipv6.invflags & IP6T_INV_PROTO)) { + DEBUGP("REJECTv6: TCP_RESET illegal for non-tcp\n"); + return 0; + } + } + + return 1; +} + +static struct ip6t_target ip6t_reject_reg += { { NULL, NULL }, "REJECT", reject6_target, check, NULL, THIS_MODULE }; + +static int __init init(void) +{ + if (ip6t_register_target(&ip6t_reject_reg)) + return -EINVAL; + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_reject_reg); +} + +module_init(init); +module_exit(fini); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_ROUTE.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_ROUTE.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_ROUTE.c 2003-12-10 23:14:08.745625160 +0100 @@ -0,0 +1,289 @@ +/* + * This implements the ROUTE v6 target, which enables you to setup unusual + * routes not supported by the standard kernel routing table. + * + * Copyright (C) 2003 Cedric de Launois + * + * v 1.0 2003/08/05 + * + * This software is distributed under GNU GPL v2, 1991 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 1 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +#define NIP6(addr) \ + ntohs((addr).s6_addr16[0]), \ + ntohs((addr).s6_addr16[1]), \ + ntohs((addr).s6_addr16[2]), \ + ntohs((addr).s6_addr16[3]), \ + ntohs((addr).s6_addr16[4]), \ + ntohs((addr).s6_addr16[5]), \ + ntohs((addr).s6_addr16[6]), \ + ntohs((addr).s6_addr16[7]) + +/* Route the packet according to the routing keys specified in + * route_info. Keys are : + * - ifindex : + * 0 if no oif preferred, + * otherwise set to the index of the desired oif + * - route_info->gw : + * 0 if no gateway specified, + * otherwise set to the next host to which the pkt must be routed + * If success, skb->dev is the output device to which the packet must + * be sent and skb->dst is not NULL + * + * RETURN: 1 if the packet was succesfully routed to the + * destination desired + * 0 if the kernel routing table could not route the packet + * according to the keys specified + */ +static int +route6(struct sk_buff *skb, + unsigned int ifindex, + const struct ip6t_route_target_info *route_info) +{ + struct rt6_info *rt = NULL; + struct ipv6hdr *ipv6h = skb->nh.ipv6h; + struct in6_addr *gw = (struct in6_addr*)&route_info->gw; + + DEBUGP("ip6t_ROUTE: called with: "); + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw)); + DEBUGP("OUT=%s\n", route_info->oif); + + if (ipv6_addr_any(gw)) + rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1); + else + rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1); + + if (!rt) + goto no_route; + + DEBUGP("ip6t_ROUTE: routing gives: "); + DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr)); + DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway)); + DEBUGP("OUT=%s\n", rt->rt6i_dev->name); + + if (ifindex && rt->rt6i_dev->ifindex!=ifindex) + goto wrong_route; + + if (!rt->rt6i_nexthop) { + DEBUGP("ip6t_ROUTE: discovering neighbour\n"); + rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr); + } + + /* Drop old route. */ + dst_release(skb->dst); + skb->dst = &rt->u.dst; + skb->dev = rt->rt6i_dev; + return 1; + + wrong_route: + dst_release(&rt->u.dst); + no_route: + if (!net_ratelimit()) + return 0; + + printk("ip6t_ROUTE: no explicit route found "); + if (ifindex) + printk("via interface %s ", route_info->oif); + if (!ipv6_addr_any(gw)) + printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw)); + printk("\n"); + return 0; +} + + +/* Stolen from ip6_output_finish + * PRE : skb->dev is set to the device we are leaving by + * skb->dst is not NULL + * POST: the packet is sent with the link layer header pushed + * the packet is destroyed + */ +static void ip_direct_send(struct sk_buff *skb) +{ + struct dst_entry *dst = skb->dst; + struct hh_cache *hh = dst->hh; + + if (hh) { + read_lock_bh(&hh->hh_lock); + memcpy(skb->data - 16, hh->hh_data, 16); + read_unlock_bh(&hh->hh_lock); + skb_push(skb, hh->hh_len); + hh->hh_output(skb); + } else if (dst->neighbour) + dst->neighbour->output(skb); + else { + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n"); + kfree_skb(skb); + } +} + + +static unsigned int +route6_oif(const struct ip6t_route_target_info *route_info, + struct sk_buff *skb) +{ + unsigned int ifindex = 0; + struct net_device *dev_out = NULL; + + /* The user set the interface name to use. + * Getting the current interface index. + */ + if ((dev_out = dev_get_by_name(route_info->oif))) { + ifindex = dev_out->ifindex; + } else { + /* Unknown interface name : packet dropped */ + if (net_ratelimit()) + DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif); + + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + else + return NF_DROP; + } + + /* Trying the standard way of routing packets */ + if (route6(skb, ifindex, route_info)) { + dev_put(dev_out); + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + } else + return NF_DROP; +} + + +static unsigned int +route6_gw(const struct ip6t_route_target_info *route_info, + struct sk_buff *skb) +{ + if (route6(skb, 0, route_info)) { + if (route_info->flags & IP6T_ROUTE_CONTINUE) + return IP6T_CONTINUE; + + ip_direct_send(skb); + return NF_STOLEN; + } else + return NF_DROP; +} + + +static unsigned int +ip6t_route_target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + const struct ip6t_route_target_info *route_info = targinfo; + struct sk_buff *skb = *pskb; + struct in6_addr *gw = (struct in6_addr*)&route_info->gw; + + if (route_info->flags & IP6T_ROUTE_CONTINUE) + goto do_it; + + /* If we are at PREROUTING or INPUT hook + * the TTL isn't decreased by the IP stack + */ + if (hooknum == NF_IP6_PRE_ROUTING || + hooknum == NF_IP6_LOCAL_IN) { + + struct ipv6hdr *ipv6h = skb->nh.ipv6h; + + if (ipv6h->hop_limit <= 1) { + /* Force OUTPUT device used as source address */ + skb->dev = skb->dst->dev; + + icmpv6_send(skb, ICMPV6_TIME_EXCEED, + ICMPV6_EXC_HOPLIMIT, 0, skb->dev); + + return NF_DROP; + } + + ipv6h->hop_limit--; + } + + + do_it: + if (route_info->oif[0]) + return route6_oif(route_info, *pskb); + + if (!ipv6_addr_any(gw)) + return route6_gw(route_info, *pskb); + + if (net_ratelimit()) + DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n"); + + return IP6T_CONTINUE; +} + + +static int +ip6t_route_checkentry(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (strcmp(tablename, "mangle") != 0) { + printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n"); + return 0; + } + + if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) { + printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n", + targinfosize, + IP6T_ALIGN(sizeof(struct ip6t_route_target_info))); + return 0; + } + + return 1; +} + + +static struct ip6t_target ip6t_route_reg = { + .name = "ROUTE", + .target = ip6t_route_target, + .checkentry = ip6t_route_checkentry, + .me = THIS_MODULE +}; + + +static int __init init(void) +{ + printk(KERN_DEBUG "registering ipv6 ROUTE target\n"); + if (ip6t_register_target(&ip6t_route_reg)) + return -EINVAL; + + return 0; +} + + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_route_reg); +} + +module_init(init); +module_exit(fini); +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_TRACE.c linux-2.6.0-test11/net/ipv6/netfilter/ip6t_TRACE.c --- linux-2.6.0-test11.org/net/ipv6/netfilter/ip6t_TRACE.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/ip6t_TRACE.c 2003-12-10 23:13:24.667326080 +0100 @@ -0,0 +1,69 @@ +/* This is a module which is used for setting + * the NFC_TRACE flag in the nfcache field of an skb. + */ +#include +#include + +#include + +static unsigned int +target(struct sk_buff **pskb, + unsigned int hooknum, + const struct net_device *in, + const struct net_device *out, + const void *targinfo, + void *userinfo) +{ + (*pskb)->nfcache |= NFC_TRACE; + return IP6T_CONTINUE; +} + +static int +checkentry(const char *tablename, + const struct ip6t_entry *e, + void *targinfo, + unsigned int targinfosize, + unsigned int hook_mask) +{ + if (targinfosize != 0) { + printk(KERN_WARNING "TRACE: targinfosize %u != 0\n", + targinfosize); + return 0; + } + + if (strcmp(tablename, "raw") != 0) { + printk(KERN_WARNING "TRACE: can only be called from \"raw\" table, not \"%s\"\n", tablename); + return 0; + } + + return 1; +} + +static struct ip6t_target ip6t_trace_reg = { + .name = "TRACE", + .target = target, + .checkentry = checkentry, + .destroy = NULL, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + if (ip6t_register_target(&ip6t_trace_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fini(void) +{ + ip6t_unregister_target(&ip6t_trace_reg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Netfilter Core Team "); +MODULE_DESCRIPTION("IPv6 TRACE target"); + \ Brak znaku nowej linii na koñcu pliku diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/Kconfig linux-2.6.0-test11/net/ipv6/netfilter/Kconfig --- linux-2.6.0-test11.org/net/ipv6/netfilter/Kconfig 2003-11-26 21:45:28.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/Kconfig 2003-12-10 23:13:24.665326384 +0100 @@ -217,6 +217,31 @@ To compile it as a module, choose M here. If unsure, say N. +config IP6_NF_RAW + tristate "Raw table" + depends on IP6_NF_IPTABLES + help + This option adds a `raw' table to iptables: see the man page for + iptables(8). This table is the very first in the netfilter + framework and hooks in at the PREROUTING and OUTPUT chains. + The TRACE target can be used in this table only. + + To compile it as a module, choose M here. If unsure, say N. + +config IP6_NF_TARGET_TRACE + tristate "TRACE target support" + depends on IP6_NF_RAW + help + The TRACE target allows packets to be traced as those matches + any subsequent rule in any IPv6 netfilter table/rule. The matched + rule and the packet is logged with the prefix + + TRACE: tablename/chainname/rulenum + + if the ip6t_LOG target is loaded in. + + To compile it as a module, choose M here. If unsure, say N. + #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES endmenu diff -Nur linux-2.6.0-test11.org/net/ipv6/netfilter/Makefile linux-2.6.0-test11/net/ipv6/netfilter/Makefile --- linux-2.6.0-test11.org/net/ipv6/netfilter/Makefile 2003-11-26 21:44:26.000000000 +0100 +++ linux-2.6.0-test11/net/ipv6/netfilter/Makefile 2003-12-10 23:14:08.816614368 +0100 @@ -6,8 +6,10 @@ obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o +obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o @@ -18,7 +20,16 @@ obj-$(CONFIG_IP6_NF_MATCH_OWNER) += ip6t_owner.o obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o +obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o +obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o +obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o + +obj-$(CONFIG_IP6_NF_MATCH_RANDOM) += ip6t_random.o + +obj-$(CONFIG_IP6_NF_MATCH_NTH) += ip6t_nth.o +obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o +obj-$(CONFIG_IP6_NF_TARGET_TRACE) += ip6t_TRACE.o obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o diff -Nur linux-2.6.0-test11.org/netfilter-patch-o-matic/patches linux-2.6.0-test11/netfilter-patch-o-matic/patches --- linux-2.6.0-test11.org/netfilter-patch-o-matic/patches 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.0-test11/netfilter-patch-o-matic/patches 2003-12-10 23:38:25.000000000 +0100 @@ -0,0 +1,86 @@ +./base/01_sctp_match.patch +./base/connlimit.patch +./base/dstlimit.patch +./base/fuzzy6.patch.ipv6 +./base/fuzzy.patch +./base/HL.patch.ipv6 +./base/iprange.patch +./base/ipv4options.patch +./base/IPV4OPTSSTRIP.patch +./base/mport.patch +./base/NETLINK.patch +./base/nth6.patch.ipv6 +./base/nth.patch +./base/osf.patch +./base/pool.patch +./base/psd.patch +./base/quota.patch +./base/random6.patch.ipv6 +./base/random.patch +./base/realm.patch +./base/REJECT.patch.ipv6 +./base/SAME.patch +./base/time.patch +./base/TTL.patch +./base/u32.patch +./extra/addrtype.patch +./extra/CLASSIFY.patch +./extra/condition6.patch.ipv6 +./extra/condition.patch +./extra/CONNMARK.patch +./extra/cuseeme-nat.patch +./extra/eggdrop-conntrack.patch +./extra/h323-conntrack-nat.patch +./extra/IPMARK.patch +./extra/iptables-loopcheck-speedup.patch +./extra/ipt_TARPIT.patch manual change .makefile +./extra/mms-conntrack-nat.patch +./extra/netfilter-docbook.patch manual change +./extra/ownercmd.patch.ipv6 +./extra/pptp-conntrack-nat.patch +./extra/quake3-conntrack.patch +./extra/ROUTE.patch +./extra/ROUTE.patch.ipv6 +./extra/rpc.patch +./extra/rsh.patch +./extra/rtsp-conntrack.patch +./extra/string.patch manual change .makefile +./extra/talk-conntrack-nat.patch +./extra/TCPLAG.patch +./extra/TRACE.patch +./extra/TRACE.patch.ipv6 +./extra/XOR.patch +./optimizations/ip_ct_refresh_optimization.patch +./optimizations/ip_ct_refresh_optimization_pptp.patch +./pending/23_REJECT-headroom-tcprst.patch +./pending/24_rcu.patch +./pending/25-err-ptr.patch +./pending/26-memsets.patch +./pending/40_nf-log.patch +./pending/70_expect-evict-order.patch +./pending/71_raw.patch +./submited/02_REJECT-headroom-tcprst.patch +./submited/03_260t4-mirror-remove.patch +./submited/03_physdev_bridged.patch +./submited/04_260t4-unclean-remove.patch +./submited/05_260t4-unexperimental.patch +./submited/06_260t4-cosmetic.patch +./submited/07_260t4-newmodules_iprange_SAME_NETMAP_CLASSIFY.patch +./submited/07_nonlinear_skb.patch +./submited/08_260t4_ipt-helper-kconfig.patch +./submited/09_260t4-cosmetic-physdev-author.patch +./submited/75_nathelper-udp-csum.patch +./submited/76_mangle_udp-sizecheck.patch +./submited/77_destroy-conntrack.patch +./submited/78_reject-localout.patch +./submited/80_ip_conntrack-proc.patch +./submited/82_irc-conntrack-mirc-serverlookup.patch +./submited/83_nolocalout.patch +./submited/84_local-nullbinding.patch +./submited/85_ipv6header.patch +./submited/86_getorigdst-tuple-zero.patch +./submited/87_compat-nat_setup_info.patch +./submited/89_ip_queue-maxlen.patch +./userspace/ip_queue_vwmark.patch +./userspace/ipt_REJECT-fake-source.patch +./userspace/mark-bitwise-ops.patch