Commit e3e64cb9 authored by Harald Welte's avatar Harald Welte Committed by David S. Miller

NETFILTER: New netfilter modules

o new dscp, ecn, helper, conntrack, pkttype matches
o new DSCP, ECN targets
o extended owner match (support matching of process name)
o fix ip_{conntrack,nat}_{ftp,irc}.c module load bug
o clear nfmark for REJECT-generated packets
o make functions in ipt_ah.c static
o new IPv6 length and eui64 matches
parent a1262496
/* iptables module for setting the IPv4 DSCP field
*
* (C) 2002 Harald Welte <laforge@gnumonks.org>
* based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
* This software is distributed under GNU GPL v2, 1991
*
* See RFC2474 for a description of the DSCP field within the IP Header.
*
* ipt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
*/
#ifndef _IPT_DSCP_TARGET_H
#define _IPT_DSCP_TARGET_H
#include <linux/netfilter_ipv4/ipt_dscp.h>
/* target info */
struct ipt_DSCP_info {
u_int8_t dscp;
};
#endif /* _IPT_DSCP_TARGET_H */
/* Header file for iptables ipt_ECN target
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
*
* This software is distributed under GNU GPL v2, 1991
*
* ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp
*/
#ifndef _IPT_ECN_TARGET_H
#define _IPT_ECN_TARGET_H
#include <linux/netfilter_ipv4/ipt_DSCP.h>
#define IPT_ECN_IP_MASK (~IPT_DSCP_MASK)
#define IPT_ECN_OP_SET_IP 0x01 /* set ECN bits of IPv4 header */
#define IPT_ECN_OP_SET_ECE 0x10 /* set ECE bit of TCP header */
#define IPT_ECN_OP_SET_CWR 0x20 /* set CWR bit of TCP header */
#define IPT_ECN_OP_MASK 0xce
struct ipt_ECN_info {
u_int8_t operation; /* bitset of operations */
u_int8_t ip_ect; /* ECT codepoint of IPv4 header, pre-shifted */
union {
struct {
u_int8_t ece:1, cwr:1; /* TCP ECT bits */
} tcp;
} proto;
};
#endif /* _IPT_ECN_TARGET_H */
/* Header file for kernel module to match connection tracking information.
* GPL (C) 2001 Marc Boucher (marc@mbsi.ca).
*/
#ifndef _IPT_CONNTRACK_H
#define _IPT_CONNTRACK_H
#define IPT_CONNTRACK_STATE_BIT(ctinfo) (1 << ((ctinfo)%IP_CT_IS_REPLY+1))
#define IPT_CONNTRACK_STATE_INVALID (1 << 0)
#define IPT_CONNTRACK_STATE_SNAT (1 << (IP_CT_NUMBER + 1))
#define IPT_CONNTRACK_STATE_DNAT (1 << (IP_CT_NUMBER + 2))
/* flags, invflags: */
#define IPT_CONNTRACK_STATE 0x01
#define IPT_CONNTRACK_PROTO 0x02
#define IPT_CONNTRACK_ORIGSRC 0x04
#define IPT_CONNTRACK_ORIGDST 0x08
#define IPT_CONNTRACK_REPLSRC 0x10
#define IPT_CONNTRACK_REPLDST 0x20
#define IPT_CONNTRACK_STATUS 0x40
#define IPT_CONNTRACK_EXPIRES 0x80
struct ipt_conntrack_info
{
unsigned int statemask, statusmask;
struct ip_conntrack_tuple tuple[IP_CT_DIR_MAX];
struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX];
unsigned long expires_min, expires_max;
/* Flags word */
u_int8_t flags;
/* Inverse flags */
u_int8_t invflags;
};
#endif /*_IPT_CONNTRACK_H*/
/* iptables module for matching the IPv4 DSCP field
*
* (C) 2002 Harald Welte <laforge@gnumonks.org>
* This software is distributed under GNU GPL v2, 1991
*
* See RFC2474 for a description of the DSCP field within the IP Header.
*
* ipt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
*/
#ifndef _IPT_DSCP_H
#define _IPT_DSCP_H
#define IPT_DSCP_MASK 0xfc /* 11111100 */
#define IPT_DSCP_SHIFT 2
#define IPT_DSCP_MAX 0x3f /* 00111111 */
/* match info */
struct ipt_dscp_info {
u_int8_t dscp;
u_int8_t invert;
};
#endif /* _IPT_DSCP_H */
/* iptables module for matching the ECN header in IPv4 and TCP header
*
* (C) 2002 Harald Welte <laforge@gnumonks.org>
*
* This software is distributed under GNU GPL v2, 1991
*
* ipt_ecn.h,v 1.4 2002/08/05 19:39:00 laforge Exp
*/
#ifndef _IPT_ECN_H
#define _IPT_ECN_H
#include <linux/netfilter_ipv4/ipt_dscp.h>
#define IPT_ECN_IP_MASK (~IPT_DSCP_MASK)
#define IPT_ECN_OP_MATCH_IP 0x01
#define IPT_ECN_OP_MATCH_ECE 0x10
#define IPT_ECN_OP_MATCH_CWR 0x20
#define IPT_ECN_OP_MATCH_MASK 0xce
/* match info */
struct ipt_ecn_info {
u_int8_t operation;
u_int8_t invert;
u_int8_t ip_ect;
union {
struct {
u_int8_t ect;
} tcp;
} proto;
};
#endif /* _IPT_ECN_H */
#ifndef _IPT_HELPER_H
#define _IPT_HELPER_H
struct ipt_helper_info {
int invert;
char name[30];
};
#endif /* _IPT_HELPER_H */
#ifndef _IPT_PKTTYPE_H
#define _IPT_PKTTYPE_H
struct ipt_pkttype_info {
int pkttype;
int invert;
};
#endif /*_IPT_PKTTYPE_H*/
#ifndef _IP6T_LENGTH_H
#define _IP6T_LENGTH_H
struct ip6t_length_info {
u_int16_t min, max;
u_int8_t invert;
};
#endif /*_IP6T_LENGTH_H*/
/* iptables module for setting the IPv4 DSCP field, Version 1.8
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
* based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
* This software is distributed under GNU GPL v2, 1991
*
* See RFC2474 for a description of the DSCP field within the IP Header.
*
* ipt_DSCP.c,v 1.8 2002/08/06 18:41:57 laforge Exp
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_DSCP.h>
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("IP tables DSCP modification module");
MODULE_LICENSE("GPL");
static unsigned int
target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
const void *targinfo,
void *userinfo)
{
struct iphdr *iph = (*pskb)->nh.iph;
const struct ipt_DSCP_info *dinfo = targinfo;
u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
if ((iph->tos & IPT_DSCP_MASK) != sh_dscp) {
u_int16_t diffs[2];
/* raw socket (tcpdump) may have clone of incoming
* skb: don't disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
iph = (*pskb)->nh.iph;
}
diffs[0] = htons(iph->tos) ^ 0xFFFF;
iph->tos = (iph->tos & ~IPT_DSCP_MASK) | sh_dscp;
diffs[1] = htons(iph->tos);
iph->check = csum_fold(csum_partial((char *)diffs,
sizeof(diffs),
iph->check^0xFFFF));
(*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)
{
const u_int8_t dscp = ((struct ipt_DSCP_info *)targinfo)->dscp;
if (targinfosize != IPT_ALIGN(sizeof(struct ipt_DSCP_info))) {
printk(KERN_WARNING "DSCP: targinfosize %u != %Zu\n",
targinfosize,
IPT_ALIGN(sizeof(struct ipt_DSCP_info)));
return 0;
}
if (strcmp(tablename, "mangle") != 0) {
printk(KERN_WARNING "DSCP: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
return 0;
}
if ((dscp > IPT_DSCP_MAX)) {
printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
return 0;
}
return 1;
}
static struct ipt_target ipt_dscp_reg
= { { NULL, NULL }, "DSCP", target, checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
if (ipt_register_target(&ipt_dscp_reg))
return -EINVAL;
return 0;
}
static void __exit fini(void)
{
ipt_unregister_target(&ipt_dscp_reg);
}
module_init(init);
module_exit(fini);
/* iptables module for the IPv4 and TCP ECN bits, Version 1.5
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
*
* This software is distributed under GNU GPL v2, 1991
*
* ipt_ECN.c,v 1.5 2002/08/18 19:36:51 laforge Exp
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ECN.h>
MODULE_LICENSE("GPL");
/* set ECT codepoint from IP header.
* return 0 in case there was no ECT codepoint
* return 1 in case ECT codepoint has been overwritten
* return < 0 in case there was error */
static int inline
set_ect_ip(struct sk_buff **pskb, struct iphdr *iph,
const struct ipt_ECN_info *einfo)
{
if ((iph->tos & IPT_ECN_IP_MASK)
!= (einfo->ip_ect & IPT_ECN_IP_MASK)) {
u_int16_t diffs[2];
/* raw socket (tcpdump) may have clone of incoming
* skb: don't disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
iph = (*pskb)->nh.iph;
}
diffs[0] = htons(iph->tos) ^ 0xFFFF;
iph->tos = iph->tos & ~IPT_ECN_IP_MASK;
iph->tos = iph->tos | (einfo->ip_ect & IPT_ECN_IP_MASK);
diffs[1] = htons(iph->tos);
iph->check = csum_fold(csum_partial((char *)diffs,
sizeof(diffs),
iph->check^0xFFFF));
(*pskb)->nfcache |= NFC_ALTERED;
return 1;
}
return 0;
}
static int inline
set_ect_tcp(struct sk_buff **pskb, struct iphdr *iph,
const struct ipt_ECN_info *einfo)
{
struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
u_int16_t *tcpflags = (u_int16_t *)tcph + 6;
u_int16_t diffs[2];
/* raw socket (tcpdump) may have clone of incoming
* skb: don't disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
iph = (*pskb)->nh.iph;
}
diffs[0] = *tcpflags;
if (einfo->operation & IPT_ECN_OP_SET_ECE
&& tcph->ece != einfo->proto.tcp.ece) {
tcph->ece = einfo->proto.tcp.ece;
}
if (einfo->operation & IPT_ECN_OP_SET_CWR
&& tcph->cwr != einfo->proto.tcp.cwr) {
tcph->cwr = einfo->proto.tcp.cwr;
}
if (diffs[0] != *tcpflags) {
diffs[0] = htons(diffs[0]) ^ 0xFFFF;
diffs[1] = htons(*tcpflags);
tcph->check = csum_fold(csum_partial((char *)diffs,
sizeof(diffs),
tcph->check^0xFFFF));
(*pskb)->nfcache |= NFC_ALTERED;
return 1;
}
return 0;
}
static unsigned int
target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
const void *targinfo,
void *userinfo)
{
struct iphdr *iph = (*pskb)->nh.iph;
const struct ipt_ECN_info *einfo = targinfo;
if (einfo->operation & IPT_ECN_OP_SET_IP)
set_ect_ip(pskb, iph, einfo);
if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
&& iph->protocol == IPPROTO_TCP)
set_ect_tcp(pskb, iph, einfo);
return IPT_CONTINUE;
}
static int
checkentry(const char *tablename,
const struct ipt_entry *e,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask)
{
const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo;
if (targinfosize != IPT_ALIGN(sizeof(struct ipt_ECN_info))) {
printk(KERN_WARNING "ECN: targinfosize %u != %Zu\n",
targinfosize,
IPT_ALIGN(sizeof(struct ipt_ECN_info)));
return 0;
}
if (strcmp(tablename, "mangle") != 0) {
printk(KERN_WARNING "ECN: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
return 0;
}
if (einfo->operation & IPT_ECN_OP_MASK) {
printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
einfo->operation);
return 0;
}
if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
einfo->ip_ect);
return 0;
}
if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
&& e->ip.proto != IPPROTO_TCP) {
printk(KERN_WARNING "ECN: cannot use TCP operations on a "
"non-tcp rule\n");
return 0;
}
return 1;
}
static struct ipt_target ipt_ecn_reg
= { { NULL, NULL }, "ECN", target, checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
if (ipt_register_target(&ipt_ecn_reg))
return -EINVAL;
return 0;
}
static void __exit fini(void)
{
ipt_unregister_target(&ipt_ecn_reg);
}
module_init(init);
module_exit(fini);
/* Kernel module to match connection tracking information.
* Superset of Rusty's minimalistic state match.
* GPL (C) 2001 Marc Boucher (marc@mbsi.ca).
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_conntrack.h>
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_conntrack_info *sinfo = matchinfo;
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
unsigned int statebit;
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
statebit = ct ? IPT_CONNTRACK_STATE_INVALID : IPT_CONNTRACK_STATE_BIT(ctinfo);
if(sinfo->flags & IPT_CONNTRACK_STATE) {
if (ct) {
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip !=
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip)
statebit |= IPT_CONNTRACK_STATE_SNAT;
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip !=
ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip)
statebit |= IPT_CONNTRACK_STATE_DNAT;
}
if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_PROTO) {
if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_STATUS) {
if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
unsigned long expires;
if(!ct)
return 0;
expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
return 0;
}
return 1;
}
static int check(const char *tablename,
const struct ipt_ip *ip,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info)))
return 0;
return 1;
}
static struct ipt_match conntrack_match
= { { NULL, NULL }, "conntrack", &match, &check, NULL, THIS_MODULE };
static int __init init(void)
{
/* NULL if ip_conntrack not a module */
if (ip_conntrack_module)
__MOD_INC_USE_COUNT(ip_conntrack_module);
return ipt_register_match(&conntrack_match);
}
static void __exit fini(void)
{
ipt_unregister_match(&conntrack_match);
if (ip_conntrack_module)
__MOD_DEC_USE_COUNT(ip_conntrack_module);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
/* IP tables module for matching the value of the IPv4 DSCP field
*
* ipt_dscp.c,v 1.3 2002/08/05 19:00:21 laforge Exp
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
*
* This software is distributed under the terms GNU GPL
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ipt_dscp.h>
#include <linux/netfilter_ipv4/ip_tables.h>
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("IP tables DSCP matching module");
MODULE_LICENSE("GPL");
static int match(const struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, const void *matchinfo,
int offset, const void *hdr, u_int16_t datalen,
int *hotdrop)
{
const struct ipt_dscp_info *info = matchinfo;
const struct iphdr *iph = skb->nh.iph;
u_int8_t sh_dscp = ((info->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
return ((iph->tos&IPT_DSCP_MASK) == sh_dscp) ^ 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_dscp_info)))
return 0;
return 1;
}
static struct ipt_match dscp_match = { { NULL, NULL }, "dscp", &match,
&checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ipt_register_match(&dscp_match);
}
static void __exit fini(void)
{
ipt_unregister_match(&dscp_match);
}
module_init(init);
module_exit(fini);
/* IP tables module for matching the value of the IPv4 and TCP ECN bits
*
* ipt_ecn.c,v 1.3 2002/05/29 15:09:00 laforge Exp
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
*
* This software is distributed under the terms GNU GPL v2
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ecn.h>
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("IP tables ECN matching module");
MODULE_LICENSE("GPL");
static inline int match_ip(const struct sk_buff *skb,
const struct iphdr *iph,
const struct ipt_ecn_info *einfo)
{
return ((iph->tos&IPT_ECN_IP_MASK) == einfo->ip_ect);
}
static inline int match_tcp(const struct sk_buff *skb,
const struct iphdr *iph,
const struct ipt_ecn_info *einfo)
{
struct tcphdr *tcph = (void *)iph + iph->ihl*4;
if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
if (tcph->ece == 1)
return 0;
} else {
if (tcph->ece == 0)
return 0;
}
}
if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
if (tcph->cwr == 1)
return 0;
} else {
if (tcph->cwr == 0)
return 0;
}
}
return 1;
}
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_ecn_info *info = matchinfo;
const struct iphdr *iph = skb->nh.iph;
if (info->operation & IPT_ECN_OP_MATCH_IP)
if (!match_ip(skb, iph, info))
return 0;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
if (iph->protocol != IPPROTO_TCP)
return 0;
if (!match_tcp(skb, iph, info))
return 0;
}
return 1;
}
static int checkentry(const char *tablename, const struct ipt_ip *ip,
void *matchinfo, unsigned int matchsize,
unsigned int hook_mask)
{
const struct ipt_ecn_info *info = matchinfo;
if (matchsize != IPT_ALIGN(sizeof(struct ipt_ecn_info)))
return 0;
if (info->operation & IPT_ECN_OP_MATCH_MASK)
return 0;
if (info->invert & IPT_ECN_OP_MATCH_MASK)
return 0;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
&& ip->proto != IPPROTO_TCP) {
printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
" non-tcp packets\n");
return 0;
}
return 1;
}
static struct ipt_match ecn_match = { { NULL, NULL }, "ecn", &match,
&checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ipt_register_match(&ecn_match);
}
static void __exit fini(void)
{
ipt_unregister_match(&ecn_match);
}
module_init(init);
module_exit(fini);
/*
* iptables module to match on related connections
* (c) 2001 Martin Josefsson <gandalf@wlug.westbo.se>
*
* Released under the terms of GNU GPLv2.
*
* 19 Mar 2002 Harald Welte <laforge@gnumonks.org>:
* - Port to newnat infrastructure
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_helper.h>
MODULE_LICENSE("GPL");
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
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_helper_info *info = matchinfo;
struct ip_conntrack_expect *exp;
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
if (!ct) {
DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
return 0;
}
if (!ct->master) {
DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
return 0;
}
exp = ct->master;
if (!exp->expectant) {
DEBUGP("ipt_helper: expectation %p without expectant !?!\n",
exp);
return 0;
}
if (!exp->expectant->helper) {
DEBUGP("ipt_helper: master ct %p has no helper\n",
exp->expectant);
return 0;
}
DEBUGP("master's name = %s , info->name = %s\n",
exp->expectant->helper->name, info->name);
return !strncmp(exp->expectant->helper->name, info->name,
strlen(exp->expectant->helper->name)) ^ info->invert;
}
static int check(const char *tablename,
const struct ipt_ip *ip,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
struct ipt_helper_info *info = matchinfo;
info->name[29] = '\0';
/* verify size */
if (matchsize != IPT_ALIGN(sizeof(struct ipt_helper_info)))
return 0;
/* verify that we actually should match anything */
if ( strlen(info->name) == 0 )
return 0;
return 1;
}
static struct ipt_match helper_match
= { { NULL, NULL }, "helper", &match, &check, NULL, THIS_MODULE };
static int __init init(void)
{
/* NULL if ip_conntrack not a module */
if (ip_conntrack_module)
__MOD_INC_USE_COUNT(ip_conntrack_module);
return ipt_register_match(&helper_match);
}
static void __exit fini(void)
{
ipt_unregister_match(&helper_match);
if (ip_conntrack_module)
__MOD_DEC_USE_COUNT(ip_conntrack_module);
}
module_init(init);
module_exit(fini);
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/netfilter_ipv4/ipt_pkttype.h>
#include <linux/netfilter_ipv4/ip_tables.h>
MODULE_LICENSE("GPL");
static int match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
const void *hdr,
u_int16_t datalen,
int *hotdrop)
{
const struct ipt_pkttype_info *info = matchinfo;
return (skb->pkt_type == info->pkttype) ^ info->invert;
}
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_LOCAL_IN)
| (1 << NF_IP_FORWARD))) {
printk("ipt_pkttype: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
return 0;
}
*/
if (matchsize != IPT_ALIGN(sizeof(struct ipt_pkttype_info)))
return 0;
return 1;
}
static struct ipt_match pkttype_match
= { { NULL, NULL }, "pkttype", &match, &checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ipt_register_match(&pkttype_match);
}
static void __exit fini(void)
{
ipt_unregister_match(&pkttype_match);
}
module_init(init);
module_exit(fini);
/* Kernel module to match EUI64 address parameters. */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ipv6.h>
#include <linux/if_ether.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
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)
{
unsigned char eui64[8];
int i=0;
if ( !(skb->mac.raw >= skb->head
&& (skb->mac.raw + ETH_HLEN) <= skb->data)
&& offset != 0) {
*hotdrop = 1;
return 0;
}
memset(eui64, 0, sizeof(eui64));
if (skb->mac.ethernet->h_proto == ntohs(ETH_P_IPV6)) {
if (skb->nh.ipv6h->version == 0x6) {
memcpy(eui64, skb->mac.ethernet->h_source, 3);
memcpy(eui64 + 5, skb->mac.ethernet->h_source + 3, 3);
eui64[3]=0xff;
eui64[4]=0xfe;
eui64[0] |= 0x02;
i=0;
while ((skb->nh.ipv6h->saddr.in6_u.u6_addr8[8+i] ==
eui64[i]) && (i<8)) i++;
if ( i == 8 )
return 1;
}
}
return 0;
}
static int
ip6t_eui64_checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
if (hook_mask
& ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
(1 << NF_IP6_PRE_ROUTING) )) {
printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
return 0;
}
if (matchsize != IP6T_ALIGN(sizeof(int)))
return 0;
return 1;
}
static struct ip6t_match eui64_match
= { { NULL, NULL }, "eui64", &match, &ip6t_eui64_checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ip6t_register_match(&eui64_match);
}
static void __exit fini(void)
{
ip6t_unregister_match(&eui64_match);
}
module_init(init);
module_exit(fini);
MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
/* Length Match - IPv6 Port */
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv6/ip6t_length.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
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 ip6t_length_info *info = matchinfo;
u_int16_t pktlen = ntohs(skb->nh.ipv6h->payload_len) + sizeof(struct ipv6hdr);
return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
}
static int
checkentry(const char *tablename,
const struct ip6t_ip6 *ip,
void *matchinfo,
unsigned int matchsize,
unsigned int hook_mask)
{
if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_length_info)))
return 0;
return 1;
}
static struct ip6t_match length_match
= { { NULL, NULL }, "length", &match, &checkentry, NULL, THIS_MODULE };
static int __init init(void)
{
return ip6t_register_match(&length_match);
}
static void __exit fini(void)
{
ip6t_unregister_match(&length_match);
}
module_init(init);
module_exit(fini);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment