static char irc_buffer[65536];
static DECLARE_LOCK(irc_buffer_lock);
+unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ unsigned int matchoff,
+ unsigned int matchlen,
+ struct ip_conntrack_expect *exp);
+EXPORT_SYMBOL_GPL(ip_nat_irc_hook);
+
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
MODULE_LICENSE("GPL");
-module_param_array(ports, int, ports_c, 0400);
+module_param_array(ports, int, &ports_c, 0400);
MODULE_PARM_DESC(ports, "port numbers of IRC servers");
module_param(max_dcc_channels, int, 0400);
MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
#define MINMATCHLEN 5
-struct module *ip_conntrack_irc = THIS_MODULE;
-
#if 0
#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \
__FILE__, __FUNCTION__ , ## args)
#define DEBUGP(format, args...)
#endif
-int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port,
- char **ad_beg_p, char **ad_end_p)
+static int parse_dcc(char *data, char *data_end, u_int32_t *ip,
+ u_int16_t *port, char **ad_beg_p, char **ad_end_p)
/* tries to get the ip_addr and port out of a dcc command
return value: -1 on failure, 0 on success
data pointer to first byte of DCC command data
return 0;
}
-static int help(struct sk_buff *skb,
+static int help(struct sk_buff **pskb,
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
unsigned int dataoff;
char *data, *data_limit, *ib_ptr;
int dir = CTINFO2DIR(ctinfo);
struct ip_conntrack_expect *exp;
- struct ip_ct_irc_expect *exp_irc_info = NULL;
-
+ u32 seq;
u_int32_t dcc_ip;
u_int16_t dcc_port;
- int i;
+ int i, ret = NF_ACCEPT;
char *addr_beg_p, *addr_end_p;
DEBUGP("entered\n");
}
/* Not a full tcp header? */
- th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+ th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return NF_ACCEPT;
/* No data? */
- dataoff = skb->nh.iph->ihl*4 + th->doff*4;
- if (dataoff >= skb->len)
+ dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
+ if (dataoff >= (*pskb)->len)
return NF_ACCEPT;
LOCK_BH(&irc_buffer_lock);
- ib_ptr = skb_header_pointer(skb, dataoff,
- skb->len - dataoff, irc_buffer);
+ ib_ptr = skb_header_pointer(*pskb, dataoff,
+ (*pskb)->len - dataoff, irc_buffer);
BUG_ON(ib_ptr == NULL);
data = ib_ptr;
- data_limit = ib_ptr + skb->len - dataoff;
+ data_limit = ib_ptr + (*pskb)->len - dataoff;
/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
* 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
}
exp = ip_conntrack_expect_alloc();
- if (exp == NULL)
+ if (exp == NULL) {
+ ret = NF_DROP;
goto out;
-
- exp_irc_info = &exp->help.exp_irc_info;
+ }
/* save position of address in dcc string,
* necessary for NAT */
DEBUGP("tcph->seq = %u\n", th->seq);
- exp->seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);
- exp_irc_info->len = (addr_end_p - addr_beg_p);
- exp_irc_info->port = dcc_port;
- DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
- exp->seq, (addr_end_p - _data), exp_irc_info->len);
+ seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);
+ /* We refer to the reverse direction ("!dir")
+ * tuples here, because we're expecting
+ * something in the other * direction.
+ * Doesn't matter unless NAT is happening. */
exp->tuple = ((struct ip_conntrack_tuple)
{ { 0, { 0 } },
- { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } },
+ { ct->tuplehash[!dir].tuple.dst.ip,
+ { .tcp = { htons(dcc_port) } },
IPPROTO_TCP }});
exp->mask = ((struct ip_conntrack_tuple)
{ { 0, { 0 } },
- { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
-
+ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
exp->expectfn = NULL;
-
- 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));
-
- ip_conntrack_expect_related(exp, ct);
-
+ exp->master = ct;
+ if (ip_nat_irc_hook)
+ ret = ip_nat_irc_hook(pskb, ctinfo,
+ addr_beg_p - ib_ptr,
+ addr_end_p - addr_beg_p,
+ exp);
+ else if (ip_conntrack_expect_related(exp) != 0) {
+ ip_conntrack_expect_free(exp);
+ ret = NF_DROP;
+ }
goto out;
} /* for .. NUM_DCCPROTO */
} /* while data < ... */
out:
UNLOCK_BH(&irc_buffer_lock);
- return NF_ACCEPT;
+ return ret;
}
static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
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->mask.dst.protonum = 0xFF;
hlpr->max_expected = max_dcc_channels;
hlpr->timeout = dcc_timeout;
- hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
- hlpr->me = ip_conntrack_irc;
+ hlpr->me = THIS_MODULE;
hlpr->help = help;
tmpname = &irc_names[i][0];
}
}
-PROVIDES_CONNTRACK(irc);
-
module_init(init);
module_exit(fini);