diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_helpers.h linux-2.6.5-rc1/include/linux/netfilter_helpers.h --- linux-2.6.5-rc1.org/include/linux/netfilter_helpers.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_helpers.h 2004-03-16 12:04:49.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack.h 2004-03-16 12:00:23.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack.h 2004-03-16 12:04:49.000000000 +0000 @@ -64,6 +64,7 @@ }; /* Add protocol helper include file here */ +#include #include #include #include @@ -71,6 +72,8 @@ /* per expectation: application helper private data */ union ip_conntrack_expect_help { /* insert conntrack helper private data (expect) here */ + struct ip_ct_rtsp_expect exp_rtsp_info; + struct ip_ct_rtsp_master ct_rtsp_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; @@ -206,6 +209,10 @@ } nat; #endif /* CONFIG_IP_NF_NAT_NEEDED */ +#if defined(CONFIG_IP_NF_CONNTRACK_MARK) + unsigned long mark; +#endif + }; /* get master conntrack via master expectation */ diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rpc.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rpc.h 2004-03-16 12:04:46.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2004-03-16 12:04:49.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_CONNMARK.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_CONNMARK.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_CONNMARK.h 2004-03-16 12:04:09.000000000 +0000 @@ -0,0 +1,25 @@ +#ifndef _IPT_CONNMARK_H_target +#define _IPT_CONNMARK_H_target + +/* Copyright (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * 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. + */ + +enum { + IPT_CONNMARK_SET = 0, + IPT_CONNMARK_SAVE, + IPT_CONNMARK_RESTORE +}; + +struct ipt_connmark_target_info { + unsigned long mark; + unsigned long mask; + u_int8_t mode; +}; + +#endif /*_IPT_CONNMARK_H_target*/ diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_IPMARK.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_IPMARK.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_IPMARK.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_IPMARK.h 2004-03-16 12:04:10.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_XOR.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_XOR.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_XOR.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_XOR.h 2004-03-16 12:04:18.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_addrtype.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_addrtype.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_addrtype.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_addrtype.h 2004-03-16 12:04:20.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_connmark.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_connmark.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_connmark.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_connmark.h 2004-03-16 12:04:09.000000000 +0000 @@ -0,0 +1,18 @@ +#ifndef _IPT_CONNMARK_H +#define _IPT_CONNMARK_H + +/* Copyright (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * 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. + */ + +struct ipt_connmark_info { + unsigned long mark, mask; + u_int8_t invert; +}; + +#endif /*_IPT_CONNMARK_H*/ diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_policy.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_policy.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_policy.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_policy.h 2004-03-16 12:04:45.000000000 +0000 @@ -0,0 +1,52 @@ +#ifndef _IPT_POLICY_H +#define _IPT_POLICY_H + +#define POLICY_MAX_ELEM 4 + +enum ipt_policy_flags +{ + POLICY_MATCH_IN = 0x1, + POLICY_MATCH_OUT = 0x2, + POLICY_MATCH_NONE = 0x4, + POLICY_MATCH_STRICT = 0x8, +}; + +enum ipt_policy_modes +{ + POLICY_MODE_TRANSPORT, + POLICY_MODE_TUNNEL +}; + +struct ipt_policy_spec +{ + u_int8_t saddr:1, + daddr:1, + proto:1, + mode:1, + spi:1, + reqid:1; +}; + +struct ipt_policy_elem +{ + u_int32_t saddr; + u_int32_t smask; + u_int32_t daddr; + u_int32_t dmask; + u_int32_t spi; + u_int32_t reqid; + u_int8_t proto; + u_int8_t mode; + + struct ipt_policy_spec match; + struct ipt_policy_spec invert; +}; + +struct ipt_policy_info +{ + struct ipt_policy_elem pol[POLICY_MAX_ELEM]; + u_int16_t flags; + u_int16_t len; +}; + +#endif /* _IPT_POLICY_H */ diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_rpc.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_rpc.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_rpc.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_rpc.h 2004-03-16 12:04:46.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_string.h linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_string.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv4/ipt_string.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv4/ipt_string.h 2004-03-16 12:06:26.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_owner.h linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_owner.h --- linux-2.6.5-rc1.org/include/linux/netfilter_ipv6/ip6t_owner.h 2004-03-16 05:46:45.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_ipv6/ip6t_owner.h 2004-03-16 12:04:42.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/linux/netfilter_mime.h linux-2.6.5-rc1/include/linux/netfilter_mime.h --- linux-2.6.5-rc1.org/include/linux/netfilter_mime.h 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/include/linux/netfilter_mime.h 2004-03-16 12:04:49.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/include/net/tcp.h linux-2.6.5-rc1/include/net/tcp.h --- linux-2.6.5-rc1.org/include/net/tcp.h 2004-03-16 05:45:33.000000000 +0000 +++ linux-2.6.5-rc1/include/net/tcp.h 2004-03-16 12:04:38.000000000 +0000 @@ -162,6 +162,7 @@ extern void tcp_bucket_unlock(struct sock *sk); extern int tcp_port_rover; extern struct sock *tcp_v4_lookup_listener(u32 addr, unsigned short hnum, int dif); +extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 hnum, int dif); /* These are AF independent. */ static __inline__ int tcp_bhashfn(__u16 lport) diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/include/net/udp.h linux-2.6.5-rc1/include/net/udp.h --- linux-2.6.5-rc1.org/include/net/udp.h 2004-03-16 05:47:17.000000000 +0000 +++ linux-2.6.5-rc1/include/net/udp.h 2004-03-16 12:04:38.000000000 +0000 @@ -74,6 +74,8 @@ extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int udp_disconnect(struct sock *sk, int flags); +extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); + DECLARE_SNMP_STAT(struct udp_mib, udp_statistics); #define UDP_INC_STATS(field) SNMP_INC_STATS(udp_statistics, field) #define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field) diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/Kconfig linux-2.6.5-rc1/net/ipv4/netfilter/Kconfig --- linux-2.6.5-rc1.org/net/ipv4/netfilter/Kconfig 2004-03-16 12:00:23.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/Kconfig 2004-03-16 12:06:26.000000000 +0000 @@ -672,5 +672,61 @@ depends on IP_NF_IPTABLES help +config IP_NF_CONNTRACK_MARK + bool 'Connection mark tracking support' +config IP_NF_TARGET_CONNMARK + tristate 'CONNMARK target support' + depends on IP_NF_MANGLE +config IP_NF_MATCH_CONNMARK + tristate ' Connection mark match support' + depends on IP_NF_IPTABLES + help + +config IP_NF_TARGET_IPMARK + tristate 'IPMARK target support' + depends on IP_NF_MANGLE + help + +config IP_NF_TARGET_XOR + tristate 'XOR target support' + depends on IP_NF_MANGLE + help + +config IP_NF_MATCH_ADDRTYPE + tristate 'address type match support' + depends on IP_NF_IPTABLES + help + +config IP_NF_MATCH_POLICY + tristate "IPsec policy match support" + depends on IP_NF_IPTABLES && XFRM + help + Policy matching allows you to match packets based on the + IPsec policy that was used during decapsulation/will + be used during encapsulation. + + To compile it as a module, choose M here. If unsure, say N. + help + +config IP_NF_MATCH_RPC + tristate 'RPC match support' + depends on IP_NF_CONNTRACK && IP_NF_IPTABLES + help + +config IP_NF_NAT_RTSP + tristate + depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n + default IP_NF_NAT if IP_NF_RTSP=y + default m if IP_NF_RTSP=m +config IP_NF_RTSP + tristate ' RTSP protocol support' + depends on IP_NF_CONNTRACK + help + +config IP_NF_MATCH_STRING + tristate 'String match support' + depends on IP_NF_IPTABLES + help + endmenu diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/Makefile linux-2.6.5-rc1/net/ipv4/netfilter/Makefile --- linux-2.6.5-rc1.org/net/ipv4/netfilter/Makefile 2004-03-16 12:00:23.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/Makefile 2004-03-16 12:06:26.000000000 +0000 @@ -20,6 +20,14 @@ obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o # connection tracking helpers + +# rtsp protocol support +obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o +ifdef CONFIG_IP_NF_NAT_RTSP + export-objs += ip_conntrack_rtsp.o +endif +obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.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 @@ -41,6 +49,9 @@ 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 +export-objs += ip_conntrack_rpc_tcp.o ip_conntrack_rpc_udp.o + obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o obj-$(CONFIG_IP_NF_MATCH_SCTP) += ipt_sctp.o @@ -48,6 +59,7 @@ obj-$(CONFIG_IP_NF_MATCH_DSTLIMIT) += ipt_dstlimit.o obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o +obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o @@ -78,12 +90,15 @@ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.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 +obj-$(CONFIG_IP_NF_MATCH_POLICY) += ipt_policy.o # targets obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o @@ -91,6 +106,7 @@ 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_IMQ) += ipt_IMQ.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o @@ -99,6 +115,8 @@ 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_CONNMARK) += ipt_CONNMARK.o obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o obj-$(CONFIG_IP_NF_TARGET_IPV4OPTSSTRIP) += ipt_IPV4OPTSSTRIP.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_tcp.c 2004-03-16 12:04:46.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_udp.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rpc_udp.c 2004-03-16 12:04:46.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rtsp.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_rtsp.c 2004-03-16 12:04:49.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-16 12:00:23.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_conntrack_standalone.c 2004-03-16 12:04:09.000000000 +0000 @@ -110,6 +110,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; diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_nat_rtsp.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_nat_rtsp.c 2004-03-16 12:04:49.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_tables.c linux-2.6.5-rc1/net/ipv4/netfilter/ip_tables.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ip_tables.c 2004-03-16 05:45:50.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ip_tables.c 2004-03-16 12:04:36.000000000 +0000 @@ -8,6 +8,10 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * + * 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 @@ -498,6 +502,9 @@ { unsigned int hook; + /* 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 */ for (hook = 0; hook < NF_IP_NUMHOOKS; hook++) { @@ -510,6 +517,7 @@ /* Set initial back pointer. */ e->counters.pcnt = pos; + memset(been, 0, newinfo->size); for (;;) { struct ipt_standard_target *t @@ -518,6 +526,7 @@ 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 @@ -565,10 +574,14 @@ } 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); } else { @@ -584,6 +597,7 @@ next: duprintf("Finished chain %u\n", hook); } + vfree(been); return 1; } diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_CONNMARK.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_CONNMARK.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_CONNMARK.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_CONNMARK.c 2004-03-16 12:04:09.000000000 +0000 @@ -0,0 +1,118 @@ +/* This kernel module is used to modify the connection mark values, or + * to optionally restore the skb nfmark from the connection mark + * + * Copyright (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * 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 + */ +#include +#include +#include +#include + +MODULE_AUTHOR("Henrik Nordstrom "); +MODULE_DESCRIPTION("IP tables CONNMARK matching module"); +MODULE_LICENSE("GPL"); + +#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) +{ + const struct ipt_connmark_target_info *markinfo = targinfo; + unsigned long diff; + unsigned long nfmark; + unsigned long newmark; + + enum ip_conntrack_info ctinfo; + struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); + if (ct) { + switch(markinfo->mode) { + case IPT_CONNMARK_SET: + newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; + if (newmark != ct->mark) + ct->mark = newmark; + break; + case IPT_CONNMARK_SAVE: + newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); + if (ct->mark != newmark) + ct->mark = newmark; + break; + case IPT_CONNMARK_RESTORE: + nfmark = (*pskb)->nfmark; + diff = (ct->mark ^ nfmark & markinfo->mask); + if (diff != 0) { + (*pskb)->nfmark = nfmark ^ diff; + (*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 = { + .name = "CONNMARK", + .target = &target, + .checkentry = &checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_target(&ipt_connmark_reg); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_connmark_reg); +} + +module_init(init); +module_exit(fini); diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_IPMARK.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_IPMARK.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_IPMARK.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_IPMARK.c 2004-03-16 12:04:10.000000000 +0000 @@ -0,0 +1,81 @@ +/* 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, + const struct net_device *in, + const struct net_device *out, + unsigned int hooknum, + const void *targinfo, + void *userinfo) +{ + const struct ipt_ipmark_target_info *ipmarkinfo = targinfo; + struct iphdr *iph = (*pskb)->nh.iph; + unsigned long mark; + + if (ipmarkinfo->addr == IPT_IPMARK_SRC) + mark = (unsigned long) ntohl(iph->saddr); + else + mark = (unsigned long) ntohl(iph->daddr); + + 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 = { + .name = "IPMARK", + .target = target, + .checkentry = checkentry, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return ipt_register_target(&ipt_ipmark_reg); +} + +static void __exit fini(void) +{ + ipt_unregister_target(&ipt_ipmark_reg); +} + +module_init(init); +module_exit(fini); diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_XOR.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_XOR.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_XOR.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_XOR.c 2004-03-16 12:04:18.000000000 +0000 @@ -0,0 +1,117 @@ +/* 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, + const struct net_device *in, const struct net_device *out, + unsigned int hooknum, const void *targinfo, void *userinfo) +{ + struct ipt_XOR_info *info = (void *) targinfo; + struct iphdr *iph; + struct tcphdr *tcph; + struct udphdr *udph; + int i, j, k; + + if (!skb_ip_make_writable(pskb, (*pskb)->len)) + return NF_DROP; + + iph = (*pskb)->nh.iph; + + 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 = { + .name = "XOR", + .target = ipt_xor_target, + .checkentry = ipt_xor_checkentry, + .me = 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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_addrtype.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_addrtype.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_addrtype.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_addrtype.c 2004-03-16 12:04:20.000000000 +0000 @@ -0,0 +1,68 @@ +/* + * 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, 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 = { + .name = "addrtype", + .match = match, + .checkentry = checkentry, + .me = 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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_connmark.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_connmark.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_connmark.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_connmark.c 2004-03-16 12:04:09.000000000 +0000 @@ -0,0 +1,81 @@ +/* This kernel module matches connection mark values set by the + * CONNMARK target + * + * Copyright (C) 2002,2004 MARA Systems AB + * by Henrik Nordstrom + * + * 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 + */ + +#include +#include + +MODULE_AUTHOR("Henrik Nordstrom "); +MODULE_DESCRIPTION("IP tables connmark match module"); +MODULE_LICENSE("GPL"); + +#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, + 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 = { + .name = "connmark", + .match = &match, + .checkentry = &checkentry, + .me = 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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_owner.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_owner.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_owner.c 2004-03-16 05:47:19.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_owner.c 2004-03-16 12:04:38.000000000 +0000 @@ -6,12 +6,19 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * 03/26/2003 Patrick McHardy : LOCAL_IN support */ #include #include #include +#include +#include +#include #include +#include +#include #include #include @@ -21,7 +28,7 @@ MODULE_DESCRIPTION("iptables owner match"); static int -match_comm(const struct sk_buff *skb, const char *comm) +match_comm(const struct sock *sk, const char *comm) { struct task_struct *g, *p; struct files_struct *files; @@ -38,7 +45,7 @@ spin_lock(&files->file_lock); for (i=0; i < files->max_fds; i++) { if (fcheck_files(files, i) == - skb->sk->sk_socket->file) { + sk->sk_socket->file) { spin_unlock(&files->file_lock); task_unlock(p); read_unlock(&tasklist_lock); @@ -54,7 +61,7 @@ } static int -match_pid(const struct sk_buff *skb, pid_t pid) +match_pid(const struct sock *sk, pid_t pid) { struct task_struct *p; struct files_struct *files; @@ -70,7 +77,7 @@ spin_lock(&files->file_lock); for (i=0; i < files->max_fds; i++) { if (fcheck_files(files, i) == - skb->sk->sk_socket->file) { + sk->sk_socket->file) { spin_unlock(&files->file_lock); task_unlock(p); read_unlock(&tasklist_lock); @@ -86,10 +93,10 @@ } static int -match_sid(const struct sk_buff *skb, pid_t sid) +match_sid(const struct sock *sk, pid_t sid) { struct task_struct *g, *p; - struct file *file = skb->sk->sk_socket->file; + struct file *file = sk->sk_socket->file; int i, found=0; read_lock(&tasklist_lock); @@ -129,41 +136,71 @@ int *hotdrop) { const struct ipt_owner_info *info = matchinfo; + struct iphdr *iph = skb->nh.iph; + struct sock *sk = NULL; + int ret = 0; + + if (out) { + sk = skb->sk; + } else { + if (iph->protocol == IPPROTO_TCP) { + struct tcphdr *tcph = + (struct tcphdr *)((u_int32_t *)iph + iph->ihl); + sk = tcp_v4_lookup(iph->saddr, tcph->source, + iph->daddr, tcph->dest, + skb->dev->ifindex); + if (sk && sk->sk_state == TCP_TIME_WAIT) { + tcp_tw_put((struct tcp_tw_bucket *)sk); + return ret; + } + } else if (iph->protocol == IPPROTO_UDP) { + struct udphdr *udph = + (struct udphdr *)((u_int32_t *)iph + iph->ihl); + sk = udp_v4_lookup(iph->saddr, udph->source, iph->daddr, + udph->dest, skb->dev->ifindex); + } + } - if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file) - return 0; + if (!sk || !sk->sk_socket || !sk->sk_socket->file) + goto out; if(info->match & IPT_OWNER_UID) { - if ((skb->sk->sk_socket->file->f_uid != info->uid) ^ + if ((sk->sk_socket->file->f_uid != info->uid) ^ !!(info->invert & IPT_OWNER_UID)) - return 0; + goto out; } if(info->match & IPT_OWNER_GID) { - if ((skb->sk->sk_socket->file->f_gid != info->gid) ^ + if ((sk->sk_socket->file->f_gid != info->gid) ^ !!(info->invert & IPT_OWNER_GID)) - return 0; + goto out; } if(info->match & IPT_OWNER_PID) { - if (!match_pid(skb, info->pid) ^ + if (!match_pid(sk, info->pid) ^ !!(info->invert & IPT_OWNER_PID)) - return 0; + goto out; } if(info->match & IPT_OWNER_SID) { - if (!match_sid(skb, info->sid) ^ + if (!match_sid(sk, info->sid) ^ !!(info->invert & IPT_OWNER_SID)) - return 0; + goto out; } if(info->match & IPT_OWNER_COMM) { - if (!match_comm(skb, info->comm) ^ + if (!match_comm(sk, info->comm) ^ !!(info->invert & IPT_OWNER_COMM)) - return 0; + goto out; } - return 1; + ret = 1; + +out: + if (in && sk) + sock_put(sk); + + return ret; } static int @@ -173,11 +210,19 @@ unsigned int matchsize, unsigned int hook_mask) { - if (hook_mask - & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING))) { - printk("ipt_owner: only valid for LOCAL_OUT or POST_ROUTING.\n"); - return 0; - } + if (hook_mask + & ~((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_POST_ROUTING) | + (1 << NF_IP_LOCAL_IN))) { + printk("ipt_owner: only valid for LOCAL_IN, LOCAL_OUT " + "or POST_ROUTING.\n"); + return 0; + } + + if ((hook_mask & (1 << NF_IP_LOCAL_IN)) + && ip->proto != IPPROTO_TCP && ip->proto != IPPROTO_UDP) { + printk("ipt_owner: only TCP or UDP can be used in LOCAL_IN\n"); + return 0; + } if (matchsize != IPT_ALIGN(sizeof(struct ipt_owner_info))) { printk("Matchsize %u != %Zu\n", matchsize, diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_policy.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_policy.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_policy.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_policy.c 2004-03-16 12:04:45.000000000 +0000 @@ -0,0 +1,176 @@ +/* IP tables module for matching IPsec policy + * + * Copyright (c) 2004 Patrick McHardy, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("IPtables IPsec policy matching module"); +MODULE_LICENSE("GPL"); + + +static inline int +match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e) +{ +#define MISMATCH(x,y) (e->match.x && ((e->x != (y)) ^ e->invert.x)) + + if (MISMATCH(saddr, x->props.saddr.a4 & e->smask) || + MISMATCH(daddr, x->id.daddr.a4 & e->dmask) || + MISMATCH(proto, x->id.proto) || + MISMATCH(mode, x->props.mode) || + MISMATCH(spi, x->id.spi) || + MISMATCH(reqid, x->props.reqid)) + return 0; + return 1; +} + +static int +match_policy_in(const struct sk_buff *skb, const struct ipt_policy_info *info) +{ + const struct ipt_policy_elem *e; + struct sec_path *sp = skb->sp; + int strict = info->flags & POLICY_MATCH_STRICT; + int i, pos; + + if (sp == NULL) + return -1; + if (strict && info->len != sp->len) + return 0; + + for (i = sp->len - 1; i >= 0; i--) { + pos = strict ? i - sp->len + 1 : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(sp->x[i].xvec, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int +match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info) +{ + const struct ipt_policy_elem *e; + struct dst_entry *dst = skb->dst; + int strict = info->flags & POLICY_MATCH_STRICT; + int i, pos; + + if (dst->xfrm == NULL) + return -1; + + for (i = 0; dst && dst->xfrm; dst = dst->child, i++) { + pos = strict ? i : 0; + if (pos >= info->len) + return 0; + e = &info->pol[pos]; + + if (match_xfrm_state(dst->xfrm, e)) { + if (!strict) + return 1; + } else if (strict) + return 0; + } + + return strict ? 1 : 0; +} + +static int match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const void *matchinfo, int offset, int *hotdrop) +{ + const struct ipt_policy_info *info = matchinfo; + int ret; + + if (info->flags & POLICY_MATCH_IN) + ret = match_policy_in(skb, info); + else + ret = match_policy_out(skb, info); + + if (ret < 0) { + if (info->flags & POLICY_MATCH_NONE) + ret = 1; + else + ret = 0; + } else if (info->flags & POLICY_MATCH_NONE) + ret = 0; + + return ret; +} + +static int checkentry(const char *tablename, const struct ipt_ip *ip, + void *matchinfo, unsigned int matchsize, + unsigned int hook_mask) +{ + struct ipt_policy_info *info = matchinfo; + + if (matchsize != IPT_ALIGN(sizeof(*info))) { + printk(KERN_ERR "ipt_policy: matchsize %u != %u\n", + matchsize, IPT_ALIGN(sizeof(*info))); + return 0; + } + if (!(info->flags & (POLICY_MATCH_IN|POLICY_MATCH_OUT))) { + printk(KERN_ERR "ipt_policy: neither incoming nor " + "outgoing policy selected\n"); + return 0; + } + if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN) + && info->flags & POLICY_MATCH_OUT) { + printk(KERN_ERR "ipt_policy: output policy not valid in " + "PRE_ROUTING and INPUT\n"); + return 0; + } + if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT) + && info->flags & POLICY_MATCH_IN) { + printk(KERN_ERR "ipt_policy: input policy not valid in " + "POST_ROUTING and OUTPUT\n"); + return 0; + } + if (info->len > POLICY_MAX_ELEM) { + printk(KERN_ERR "ipt_policy: too many policy elements\n"); + return 0; + } + + return 1; +} + +static struct ipt_match policy_match = +{ + .name = "policy", + .match = match, + .checkentry = checkentry, + .me = THIS_MODULE, +}; + +static int __init init(void) +{ + return ipt_register_match(&policy_match); +} + +static void __exit fini(void) +{ + ipt_unregister_match(&policy_match); +} + +module_init(init); +module_exit(fini); diff -Nur --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_rpc.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_rpc.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_rpc.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_rpc.c 2004-03-16 12:04:46.000000000 +0000 @@ -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 --exclude '*.orig' linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_string.c linux-2.6.5-rc1/net/ipv4/netfilter/ipt_string.c --- linux-2.6.5-rc1.org/net/ipv4/netfilter/ipt_string.c 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.5-rc1/net/ipv4/netfilter/ipt_string.c 2004-03-16 12:06:26.000000000 +0000 @@ -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; ccomm, 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; @@ -125,6 +157,12 @@ return 0; } + if(info->match & IP6T_OWNER_COMM) { + if (!match_comm(skb, info->comm) ^ + !!(info->invert & IP6T_OWNER_COMM)) + return 0; + } + return 1; }