static int help(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { unsigned int dataoff; struct tcphdr _tcph, *th; char *data, *data_limit, *ib_ptr; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect *exp; u32 seq; u_int32_t dcc_ip; u_int16_t dcc_port; int i, ret = NF_ACCEPT; char *addr_beg_p, *addr_end_p; DEBUGP("entered\n"); /* If packet is coming from IRC server */ if (dir == IP_CT_DIR_REPLY) return NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { DEBUGP("Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } /* Not a full tcp header? */ th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, sizeof(_tcph), &_tcph); if (th == NULL) return NF_ACCEPT; /* No data? */ dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4; if (dataoff >= (*pskb)->len) return NF_ACCEPT; spin_lock_bh(&irc_buffer_lock); ib_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, irc_buffer); BUG_ON(ib_ptr == NULL); data = ib_ptr; 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 */ while (data < (data_limit - (19 + MINMATCHLEN))) { if (memcmp(data, "\1DCC ", 5)) { data++; continue; } data += 5; /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", NIPQUAD(iph->saddr), ntohs(th->source), NIPQUAD(iph->daddr), ntohs(th->dest)); for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { /* no match */ continue; } DEBUGP("DCC %s detected\n", dccprotos[i]); data += strlen(dccprotos[i]); /* we have at least * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid * data left (== 14/13 bytes) */ if (parse_dcc((char *)data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { /* unable to parse */ DEBUGP("unable to parse dcc command\n"); continue; } DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", HIPQUAD(dcc_ip), dcc_port); /* dcc_ip can be the internal OR external (NAT'ed) IP * Tiago Sousa <*****@*****.**> */ if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip) && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) { if (net_ratelimit()) printk(KERN_WARNING "Forged DCC command from " "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", NIPQUAD(ct->tuplehash[dir].tuple.src.ip), HIPQUAD(dcc_ip), dcc_port); continue; } exp = ip_conntrack_expect_alloc(ct); if (exp == NULL) { ret = NF_DROP; goto out; } /* save position of address in dcc string, * necessary for NAT */ DEBUGP("tcph->seq = %u\n", th->seq); 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.dst.ip, { .tcp = { htons(dcc_port) } }, IPPROTO_TCP }});
static int help(struct sk_buff *skb, unsigned int protoff, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { unsigned int dataoff; const struct iphdr *iph; const struct tcphdr *th; struct tcphdr _tcph; const char *data_limit; char *data, *ib_ptr; int dir = CTINFO2DIR(ctinfo); struct nf_conntrack_expect *exp; struct nf_conntrack_tuple *tuple; __be32 dcc_ip; u_int16_t dcc_port; __be16 port; int i, ret = NF_ACCEPT; char *addr_beg_p, *addr_end_p; typeof(nf_nat_irc_hook) nf_nat_irc; /* If packet is coming from IRC server */ if (dir == IP_CT_DIR_REPLY) return NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY) return NF_ACCEPT; /* Not a full tcp header? */ th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); if (th == NULL) return NF_ACCEPT; /* No data? */ dataoff = protoff + th->doff*4; if (dataoff >= skb->len) return NF_ACCEPT; spin_lock_bh(&irc_buffer_lock); ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff, irc_buffer); BUG_ON(ib_ptr == NULL); data = ib_ptr; data_limit = ib_ptr + skb->len - dataoff; /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ while (data < data_limit - (19 + MINMATCHLEN)) { if (memcmp(data, "\1DCC ", 5)) { data++; continue; } data += 5; /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ iph = ip_hdr(skb); pr_debug("DCC found in master %pI4:%u %pI4:%u\n", &iph->saddr, ntohs(th->source), &iph->daddr, ntohs(th->dest)); for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { /* no match */ continue; } data += strlen(dccprotos[i]); pr_debug("DCC %s detected\n", dccprotos[i]); /* we have at least * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid * data left (== 14/13 bytes) */ if (parse_dcc(data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { pr_debug("unable to parse dcc command\n"); continue; } pr_debug("DCC bound ip/port: %pI4:%u\n", &dcc_ip, dcc_port); /* dcc_ip can be the internal OR external (NAT'ed) IP */ tuple = &ct->tuplehash[dir].tuple; if (tuple->src.u3.ip != dcc_ip && tuple->dst.u3.ip != dcc_ip) { net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", &tuple->src.u3.ip, &dcc_ip, dcc_port); continue; } exp = nf_ct_expect_alloc(ct); if (exp == NULL) { nf_ct_helper_log(skb, ct, "cannot alloc expectation"); ret = NF_DROP; goto out; } tuple = &ct->tuplehash[!dir].tuple; port = htons(dcc_port); nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, tuple->src.l3num, NULL, &tuple->dst.u3, IPPROTO_TCP, NULL, &port); nf_nat_irc = rcu_dereference(nf_nat_irc_hook); if (nf_nat_irc && ct->status & IPS_NAT_MASK) ret = nf_nat_irc(skb, ctinfo, protoff, addr_beg_p - ib_ptr, addr_end_p - addr_beg_p, exp); else if (nf_ct_expect_related(exp) != 0) { nf_ct_helper_log(skb, ct, "cannot add expectation"); ret = NF_DROP; } nf_ct_expect_put(exp); goto out; } } out: spin_unlock_bh(&irc_buffer_lock); return ret; }
void io_loop(void) { int r, i, errv, errlen = sizeof(errv); struct timeval tv = { 1, 0 }; struct sockaddr_in sin; size_t ssin = sizeof(sin); char buffer[BUFSIZE]; sock_t *sock, *tmp; memset(buffer, 0, BUFSIZE); loop: /* wiz is leet */ FD_ZERO(&me.readfds); FD_ZERO(&me.writefds); for (sock = main_sock; sock;) { if (sock->flags & SOCK_DEL) { tmp = sock->next; del_sock(sock); sock = tmp; continue; } if (sock->flags & (SOCK_LISTEN|SOCK_CONN)) FD_SET(sock->socket, &me.readfds); else FD_SET(sock->socket, &me.writefds); sock = sock->next; } while ((r = select(FD_SETSIZE, &me.readfds, &me.writefds, NULL, &tv)) == -1) if (errno != EINTR) { log("FATAL! select() == -1: %s", ERR); exit(1); } do_events(time(NULL)); for (sock = main_sock; r > 0 && sock;) { if (FD_ISSET(sock->socket, &me.readfds) && r--) { if (sock->flags & SOCK_LISTEN) { memset(&sin, 0, sizeof(sin)); if ((i = accept(sock->socket, (struct sockaddr *)&sin, &ssin)) == -1) goto nextsock; log("NET: connection from %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); tmp = add_sock_to_list(); if ((tmp->socket = nonblock_sock(i)) == -1) { del_sock(tmp); goto nextsock; } else if (!(tmp->fd = fdopen(tmp->socket, "r"))) { log("fdopen(%d) failed: %s", tmp->socket, strerror(errno)); del_sock(tmp); goto nextsock; } tmp->conn = time(NULL); tmp->addr = sin.sin_addr; tmp->port = ntohs(sin.sin_port); tmp->buffer = leetcalloc(BUFSIZE, 1); tmp->flags |= (SOCK_CONN|sock->flags); tmp->flags &= ~SOCK_LISTEN; greet_dcc(tmp); goto nextsock; } if (!fgets(sock->buffer, BUFSIZE, sock->fd)) { errv = 0; if (getsockopt(sock->socket, SOL_SOCKET, SO_ERROR, &errv, &errlen) < 0) { log("NET: getsockopt(SO_ERROR) failed: %s", ERR); goto delsock; } goto readerr; } sock->last = time(NULL); for(i = 0; i < BUFSIZE; i++) if (sock->buffer[i] == '\r' || sock->buffer[i] == '\n') sock->buffer[i] = 0; if (sock->flags & SOCK_HUB) parse(sock->buffer); else if (sock->flags & (SOCK_DCC|SOCK_TELNET)) parse_dcc(sock, sock->buffer); memset(sock->buffer, 0, BUFSIZE); } else if (FD_ISSET(sock->socket, &me.writefds) && r--) { errv = 0; if (getsockopt(sock->socket, SOL_SOCKET, SO_ERROR, &errv, &errlen) < 0) { log("NET: getsockopt(SO_ERROR) failed: %s", ERR); goto delsock; } if (errv > 0) { if (sock->flags & SOCK_HUB) { log("HUB: error connecting to %s: %s", sock->name, strerror(errv)); alldcc("HUB: error connecting to %s: %s", sock->name, strerror(errv)); #if 0 } else if (sock->flags & SOCK_DCC && find_client(sock->name)) reply(OS, sock->name, "Error DCC connecting: %s", strerror(errv)); #else } #endif goto delsock; } if (sock->flags & SOCK_HUB) { log("HUB: connected to %s", sock->name); alldcc("HUB: connected to %s", sock->name); del_event_func(&try_next_hub); sock->conn = time(NULL); me.conn = 1; switch (me.servtype) { case SERV_IRCNN: toserv("PASS :%s\r\n", servpass); toserv("SERVER %s 1 %lu %lu J09 :%s\r\n", me.servname, time(NULL), time(NULL), me.servdesc); add_linked_server(me.servname, me.servname, me.servdesc); intro_nicks(ALL); join_channels(OS); break; case SERV_HYBRD: toserv("CAPAB :QS EX IE EOB UNKLN KLN HOPS HUB TBURST\r\n"); toserv("PASS %s :TS\r\n", servpass); toserv("SERVER %s 0 :%s\r\n", me.servname, me.servdesc); toserv("SVINFO 5 5 0 :%lu\r\n", time(NULL)); add_linked_server(me.servname, me.servname, me.servdesc); break; } } else if (sock->flags & SOCK_DCC) { log("DCC: %s connected from %s:%d", sock->name, inet_ntoa(sock->addr), sock->port); me.dcc++; } sock->flags |= SOCK_CONN; } nextsock: { sock = sock->next; continue; } readerr: { log("NET: read error from %s: %s", (sock->name ? sock->name : inet_ntoa(sock->addr)), strerror(errv)); } delsock: { sock->flags |= SOCK_DEL; goto nextsock; } }
static int help(struct sk_buff *skb, unsigned int protoff, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { unsigned int dataoff; const struct iphdr *iph; const struct tcphdr *th; struct tcphdr _tcph; const char *data_limit; char *data, *ib_ptr; int dir = CTINFO2DIR(ctinfo); struct nf_conntrack_expect *exp; struct nf_conntrack_tuple *tuple; __be32 dcc_ip; u_int16_t dcc_port; __be16 port; int i, ret = NF_ACCEPT; char *addr_beg_p, *addr_end_p; typeof(nf_nat_irc_hook) nf_nat_irc; if (dir == IP_CT_DIR_REPLY) return NF_ACCEPT; if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY) return NF_ACCEPT; th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); if (th == NULL) return NF_ACCEPT; dataoff = protoff + th->doff*4; if (dataoff >= skb->len) return NF_ACCEPT; spin_lock_bh(&irc_buffer_lock); ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff, irc_buffer); BUG_ON(ib_ptr == NULL); data = ib_ptr; data_limit = ib_ptr + skb->len - dataoff; while (data < data_limit - (19 + MINMATCHLEN)) { if (memcmp(data, "\1DCC ", 5)) { data++; continue; } data += 5; iph = ip_hdr(skb); pr_debug("DCC found in master %pI4:%u %pI4:%u\n", &iph->saddr, ntohs(th->source), &iph->daddr, ntohs(th->dest)); for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { continue; } data += strlen(dccprotos[i]); pr_debug("DCC %s detected\n", dccprotos[i]); if (parse_dcc(data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { pr_debug("unable to parse dcc command\n"); continue; } pr_debug("DCC bound ip/port: %pI4:%u\n", &dcc_ip, dcc_port); tuple = &ct->tuplehash[dir].tuple; if (tuple->src.u3.ip != dcc_ip && tuple->dst.u3.ip != dcc_ip) { if (net_ratelimit()) printk(KERN_WARNING "Forged DCC command from %pI4: %pI4:%u\n", &tuple->src.u3.ip, &dcc_ip, dcc_port); continue; } exp = nf_ct_expect_alloc(ct); if (exp == NULL) { ret = NF_DROP; goto out; } tuple = &ct->tuplehash[!dir].tuple; port = htons(dcc_port); nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, tuple->src.l3num, NULL, &tuple->dst.u3, IPPROTO_TCP, NULL, &port); nf_nat_irc = rcu_dereference(nf_nat_irc_hook); if (nf_nat_irc && ct->status & IPS_NAT_MASK) ret = nf_nat_irc(skb, ctinfo, addr_beg_p - ib_ptr, addr_end_p - addr_beg_p, exp); else if (nf_ct_expect_related(exp) != 0) ret = NF_DROP; nf_ct_expect_put(exp); goto out; } } out: spin_unlock_bh(&irc_buffer_lock); return ret; }
/* FIXME: This should be in userspace. Later. */ static int help(const struct iphdr *iph, size_t len, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ struct tcphdr *tcph = (void *) iph + iph->ihl * 4; const char *data = (const char *) tcph + tcph->doff * 4; const char *_data = data; char *data_limit; u_int32_t tcplen = len - iph->ihl * 4; u_int32_t datalen = tcplen - tcph->doff * 4; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect expect, *exp = &expect; struct ip_ct_irc_expect *exp_irc_info = &exp->help.exp_irc_info; u_int32_t dcc_ip; u_int16_t dcc_port; int i; char *addr_beg_p, *addr_end_p; DEBUGP("entered\n"); /* If packet is coming from IRC server */ if (dir == IP_CT_DIR_REPLY) return NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { DEBUGP("Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } /* Not whole TCP header? */ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { DEBUGP("tcplen = %u\n", (unsigned) tcplen); return NF_ACCEPT; } /* Checksum invalid? Ignore. */ /* FIXME: Source route IP option packets --RR */ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *) tcph, tcplen, 0))) { DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); return NF_ACCEPT; } data_limit = (char *) data + datalen; /* strlen("\1DCC SEND t AAAAAAAA P\1\n")=24 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ while (data < (data_limit - (19 + MINMATCHLEN))) { if (memcmp(data, "\1DCC ", 5)) { data++; continue; } data += 5; /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest)); for (i = 0; i < NUM_DCCPROTO; i++) { if (memcmp(data, dccprotos[i].match, dccprotos[i].matchlen)) { /* no match */ continue; } DEBUGP("DCC %s detected\n", dccprotos[i].match); data += dccprotos[i].matchlen; /* we have at least * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid * data left (== 14/13 bytes) */ if (parse_dcc((char *) data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { /* unable to parse */ DEBUGP("unable to parse dcc command\n"); continue; } DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", HIPQUAD(dcc_ip), dcc_port); if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) { if (net_ratelimit()) printk(KERN_WARNING "Forged DCC command from " "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", NIPQUAD(ct->tuplehash[dir].tuple.src.ip), HIPQUAD(dcc_ip), dcc_port); continue; } memset(&expect, 0, sizeof(expect)); LOCK_BH(&ip_irc_lock); /* save position of address in dcc string, * neccessary for NAT */ DEBUGP("tcph->seq = %u\n", tcph->seq); exp->seq = ntohl(tcph->seq) + (addr_beg_p - _data); 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); exp->tuple = ((struct ip_conntrack_tuple) { { 0, { 0 } }, { htonl(dcc_ip), { .tcp = { htons(dcc_port) } }, IPPROTO_TCP }});
static int help(struct sk_buff **pskb, unsigned int protoff, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { unsigned int dataoff; struct tcphdr _tcph, *th; char *data, *data_limit, *ib_ptr; int dir = CTINFO2DIR(ctinfo); struct nf_conntrack_expect *exp; struct nf_conntrack_tuple *tuple; u_int32_t dcc_ip; u_int16_t dcc_port; __be16 port; int i, ret = NF_ACCEPT; char *addr_beg_p, *addr_end_p; typeof(nf_nat_irc_hook) nf_nat_irc; if((alg_flag & IRC_FLAG)==0) { (*pskb)->ff_flag = ff_clr_flag((*pskb), DRV_FF_FLAG_ALG); return NF_ACCEPT; } /* If packet is coming from IRC server */ if (dir == IP_CT_DIR_REPLY) return NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) return NF_ACCEPT; /* Not a full tcp header? */ th = skb_header_pointer(*pskb, protoff, sizeof(_tcph), &_tcph); if (th == NULL) return NF_ACCEPT; /* No data? */ dataoff = protoff + th->doff*4; if (dataoff >= (*pskb)->len) return NF_ACCEPT; spin_lock_bh(&irc_buffer_lock); ib_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, irc_buffer); BUG_ON(ib_ptr == NULL); data = ib_ptr; 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 */ while (data < data_limit - (19 + MINMATCHLEN)) { if (memcmp(data, "\1DCC ", 5)) { data++; continue; } data += 5; /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", NIPQUAD(iph->saddr), ntohs(th->source), NIPQUAD(iph->daddr), ntohs(th->dest)); for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { /* no match */ continue; } data += strlen(dccprotos[i]); DEBUGP("DCC %s detected\n", dccprotos[i]); /* we have at least * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid * data left (== 14/13 bytes) */ if (parse_dcc((char *)data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { DEBUGP("unable to parse dcc command\n"); continue; } DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", HIPQUAD(dcc_ip), dcc_port); /* dcc_ip can be the internal OR external (NAT'ed) IP */ tuple = &ct->tuplehash[dir].tuple; if (tuple->src.u3.ip != htonl(dcc_ip) && tuple->dst.u3.ip != htonl(dcc_ip)) { NATALG_STAT_INC(irc_forged_command); continue; } exp = nf_conntrack_expect_alloc(ct); if (exp == NULL) { ret = NF_DROP; goto out; } tuple = &ct->tuplehash[!dir].tuple; port = htons(dcc_port); nf_conntrack_expect_init(exp, tuple->src.l3num, NULL, &tuple->dst.u3, IPPROTO_TCP, NULL, &port); nf_nat_irc = rcu_dereference(nf_nat_irc_hook); if (nf_nat_irc && ct->status & IPS_NAT_MASK) ret = nf_nat_irc(pskb, ctinfo, addr_beg_p - ib_ptr, addr_end_p - addr_beg_p, exp); else if (nf_conntrack_expect_related(exp) != 0) ret = NF_DROP; nf_conntrack_expect_put(exp); goto out; } } out: spin_unlock_bh(&irc_buffer_lock); return ret; }
static int help(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { unsigned int dataoff; struct tcphdr tcph; char *data, *data_limit; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect *exp; struct ip_ct_irc_expect *exp_irc_info = NULL; u_int32_t dcc_ip; u_int16_t dcc_port; int i; char *addr_beg_p, *addr_end_p; DEBUGP("entered\n"); /* If packet is coming from IRC server */ if (dir == IP_CT_DIR_REPLY) return NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { DEBUGP("Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } /* Not a full tcp header? */ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0) return NF_ACCEPT; /* No data? */ dataoff = skb->nh.iph->ihl*4 + tcph.doff*4; if (dataoff >= skb->len) return NF_ACCEPT; LOCK_BH(&ip_irc_lock); skb_copy_bits(skb, dataoff, irc_buffer, skb->len - dataoff); data = irc_buffer; data_limit = irc_buffer + skb->len - dataoff; /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ while (data < (data_limit - (19 + MINMATCHLEN))) { if (memcmp(data, "\1DCC ", 5)) { data++; continue; } data += 5; /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", NIPQUAD(iph->saddr), ntohs(tcph.source), NIPQUAD(iph->daddr), ntohs(tcph.dest)); for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { /* no match */ continue; } DEBUGP("DCC %s detected\n", dccprotos[i]); data += strlen(dccprotos[i]); /* we have at least * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid * data left (== 14/13 bytes) */ if (parse_dcc((char *)data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { /* unable to parse */ DEBUGP("unable to parse dcc command\n"); continue; } DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n", HIPQUAD(dcc_ip), dcc_port); /* dcc_ip can be the internal OR external (NAT'ed) IP * Tiago Sousa <*****@*****.**> */ if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip) && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) { if (net_ratelimit()) printk(KERN_WARNING "Forged DCC command from " "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", NIPQUAD(ct->tuplehash[dir].tuple.src.ip), HIPQUAD(dcc_ip), dcc_port); continue; } exp = ip_conntrack_expect_alloc(); if (exp == NULL) 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", tcph.seq); exp->seq = ntohl(tcph.seq) + (addr_beg_p - irc_buffer); 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); exp->tuple = ((struct ip_conntrack_tuple) { { 0, { 0 } }, { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } }, IPPROTO_TCP }});