static int talk_help_response(const struct iphdr *iph, size_t len, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, int talk_port, u_char mode, u_char type, u_char answer, struct talk_addr *addr) { int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect expect, *exp = &expect; struct ip_ct_talk_expect *exp_talk_info = &exp->help.exp_talk_info; DEBUGP("ip_ct_talk_help_response: %u.%u.%u.%u:%u, type %d answer %d\n", NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), type, answer); if (!(answer == SUCCESS && type == mode)) return NF_ACCEPT; memset(&expect, 0, sizeof(expect)); if (type == ANNOUNCE) { DEBUGP("ip_ct_talk_help_response: ANNOUNCE\n"); /* update the talk info */ LOCK_BH(&ip_talk_lock); exp_talk_info->port = htons(talk_port); /* expect callee client -> caller server message */ exp->tuple = ((struct ip_conntrack_tuple) { { ct->tuplehash[dir].tuple.src.ip, { 0 } }, { ct->tuplehash[dir].tuple.dst.ip,
static unsigned int pptp_nat_expected(struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, struct ip_nat_info *info) { struct ip_conntrack *master = master_ct(ct); struct ip_nat_multi_range mr; struct ip_ct_pptp_master *ct_pptp_info; struct ip_nat_pptp *nat_pptp_info; u_int32_t newsrcip, newdstip, newcid; int ret; IP_NF_ASSERT(info); IP_NF_ASSERT(master); IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); DEBUGP("we have a connection!\n"); LOCK_BH(&ip_pptp_lock); ct_pptp_info = &master->help.ct_pptp_info; nat_pptp_info = &master->nat.help.nat_pptp_info; /* need to alter GRE tuple because conntrack expectfn() used 'wrong' * (unmanipulated) values */ if (hooknum == NF_IP_PRE_ROUTING) { DEBUGP("completing tuples with NAT info \n"); /* we can do this, since we're unconfirmed */ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == htonl(ct_pptp_info->pac_call_id)) { /* assume PNS->PAC */ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); // ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.gre.key = // htonl(nat_pptp_info->pac_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(nat_pptp_info->pns_call_id); } else { /* assume PAC->PNS */ DEBUGP("WRONG DIRECTION\n"); ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = htonl(nat_pptp_info->pns_call_id); } } if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { //OsborneModify Start on August 3, 2006. //newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; //OsborneModify End. newcid = htonl(master->nat.help.nat_pptp_info.pac_call_id); mr.rangesize = 1; mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].min_ip = mr.range[0].max_ip = newdstip; mr.range[0].min = mr.range[0].max = ((union ip_conntrack_manip_proto ) { newcid });
static unsigned int help(struct ip_conntrack *ct, struct ip_conntrack_expect *exp, struct ip_nat_info *info, enum ip_conntrack_info ctinfo, unsigned int hooknum, struct sk_buff **pskb) { struct iphdr *iph = (*pskb)->nh.iph; struct tcphdr *tcph = (void *) iph + iph->ihl * 4; unsigned int datalen; int dir; struct ip_ct_irc_expect *ct_irc_info; if (!exp) DEBUGP("ip_nat_irc: no exp!!"); ct_irc_info = &exp->help.exp_irc_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("nat_irc: 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_irc_lock); /* Check wether the whole IP/address pattern is carried in the payload */ if (between(exp->seq + ct_irc_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) { if (!irc_data_fixup(ct_irc_info, ct, pskb, ctinfo, exp)) { UNLOCK_BH(&ip_irc_lock); return NF_DROP; } } else { /* Half a match? This means a partial retransmisison. It's a cracker being funky. */ if (net_ratelimit()) { printk ("IRC_NAT: partial packet %u/%u in %u/%u\n", exp->seq, ct_irc_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); } UNLOCK_BH(&ip_irc_lock); return NF_DROP; } UNLOCK_BH(&ip_irc_lock); return NF_ACCEPT; }
static int talk_help_response(struct ip_conntrack *ct, struct ip_conntrack_expect *exp, struct sk_buff **pskb, u_char type, u_char answer, struct talk_addr *addr) { u_int32_t newip; u_int16_t port; struct ip_conntrack_tuple t; struct ip_ct_talk_expect *ct_talk_info; DEBUGP("ip_nat_talk_help_response: addr: %u.%u.%u.%u:%u, type %d answer %d\n", NIPQUAD(addr->ta_addr), ntohs(addr->ta_port), type, answer); LOCK_BH(&ip_talk_lock); ct_talk_info = &exp->help.exp_talk_info; if (!(answer == SUCCESS && (type == LOOK_UP || type == ANNOUNCE) && exp != NULL)) { UNLOCK_BH(&ip_talk_lock); return NF_ACCEPT; } DEBUGP("ip_nat_talk_help_response: talkinfo port %u (%s)\n", ntohs(ct_talk_info->port), type == LOOK_UP ? "LOOK_UP" : "ANNOUNCE"); /* Change address inside packet to match way we're mapping this connection. */ newip = ct->tuplehash[type == LOOK_UP ? IP_CT_DIR_ORIGINAL : IP_CT_DIR_REPLY].tuple.dst.ip; /* We can read expect here without conntrack lock, since it's only set in ip_conntrack_talk , with ip_talk_lock held writable */ t = exp->tuple; t.dst.ip = newip; /* Try to get same port: if not, try to change it. */ for (port = ntohs(ct_talk_info->port); port != 0; port++) { if (type == LOOK_UP) t.dst.u.tcp.port = htons(port); else t.dst.u.udp.port = htons(port); if (ip_conntrack_change_expect(exp, &t) == 0) { DEBUGP("ip_nat_talk_help_response: using %u.%u.%u.%u:%u\n", NIPQUAD(newip), port); break; } } UNLOCK_BH(&ip_talk_lock); if (port == 0 || !mangle_packet(pskb, ct, newip, htons(port), addr, NULL)) return NF_DROP; return NF_ACCEPT; }
static unsigned int ftp_nat_expected(struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, struct ip_nat_info *info) { struct ip_nat_multi_range mr; u_int32_t newdstip, newsrcip, newip; struct ip_ct_ftp_expect *exp_ftp_info; struct ip_conntrack *master = master_ct(ct); IP_NF_ASSERT(info); IP_NF_ASSERT(master); IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum)))); DEBUGP("nat_expected: We have a connection!\n"); exp_ftp_info = &ct->master->help.exp_ftp_info; LOCK_BH(&ip_ftp_lock); if (exp_ftp_info->ftptype == IP_CT_FTP_PORT || exp_ftp_info->ftptype == IP_CT_FTP_EPRT) { /* PORT command: make connection go to the client. */ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; DEBUGP("nat_expected: PORT cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); } else { /* PASV command: make the connection go to the server */ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; DEBUGP("nat_expected: PASV cmd. %u.%u.%u.%u->%u.%u.%u.%u\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); } UNLOCK_BH(&ip_ftp_lock); if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) newip = newsrcip; else newip = newdstip; DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); mr.rangesize = 1; /* We don't want to manip the per-protocol, just the IPs... */ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; mr.range[0].min_ip = mr.range[0].max_ip = newip; /* ... unless we're doing a MANIP_DST, in which case, make sure we map to the correct port */ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].min = mr.range[0].max = ((union ip_conntrack_manip_proto) { htons(exp_ftp_info->port) });
/* timer function to flush queue in ULOG_FLUSH_INTERVAL time */ static void ulog_timer(unsigned long data) { DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n"); /* lock to protect against somebody modifying our structure * from ipt_ulog_target at the same time */ LOCK_BH(&ulog_lock); ulog_send(data); UNLOCK_BH(&ulog_lock); }
static unsigned int autofw_nat_expected(struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, struct ip_nat_info *info) { struct ip_nat_multi_range mr; u_int32_t newdstip, newsrcip, newip; u_int16_t port; struct ip_conntrack *master = master_ct(ct); IP_NF_ASSERT(info); IP_NF_ASSERT(master); IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum)))); DEBUGP("autofw_nat_expected: got "); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); LOCK_BH(&ip_autofw_lock); port = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all); newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; #ifdef NEW_PORT_TRIG newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; #else newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; #endif if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) newip = newsrcip; else { if (port < ntohs(ct->master->help.exp_autofw_info.dport[0]) || port > ntohs(ct->master->help.exp_autofw_info.dport[1])) { UNLOCK_BH(&ip_autofw_lock); return NF_DROP; } newip = newdstip; } mr.rangesize = 1; /* We don't want to manip the per-protocol, just the IPs... */ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; mr.range[0].min_ip = mr.range[0].max_ip = newip; /* ... unless we're doing a MANIP_DST, in which case, make sure we map to the correct port */ port -= ntohs(ct->master->help.exp_autofw_info.dport[0]); port += ntohs(ct->master->help.exp_autofw_info.to[0]); if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].min = mr.range[0].max = ((union ip_conntrack_manip_proto) { htons(port) });
/* FIXME: This should be in userspace. Later. */ static int help(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { int dir = CTINFO2DIR(ctinfo); struct tcphdr tcph; struct ip_conntrack_expect exp; int i; /* ** We only do this for the new packet */ // printk("wm_help: Conntrackinfo = %u dir=%d\n", ctinfo,dir); if ( ctinfo != IP_CT_NEW) return NF_ACCEPT; if ( dir != 0) return NF_ACCEPT; //DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); //DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0) return NF_ACCEPT; LOCK_BH(&ip_wm_lock); //for(i = WMMIN; i <= WMMIN; i++) { for(i = WMMIN; i <= WMMAX; i++) { memset(&exp, 0, sizeof(exp)); exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; exp.tuple.dst.u.udp.port = htons(i); exp.tuple.dst.protonum = IPPROTO_UDP; exp.mask.src.ip = 0xffffffff; exp.mask.dst.ip = 0xffffffff; exp.mask.dst.u.udp.port = 0xffff; exp.mask.dst.protonum = 0xffff; exp.expectfn = NULL; exp.seq = ntohl(tcph.seq); DEBUGP("wm_help: expect: "); DUMP_TUPLE(&exp.tuple); DUMP_TUPLE(&exp.mask); ip_conntrack_expect_related(&exp, ct); } UNLOCK_BH(&ip_wm_lock); return NF_ACCEPT; }
static unsigned int talk_nat_expected(struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, struct ip_nat_info *info) { struct ip_nat_multi_range mr; u_int32_t newdstip, newsrcip, newip; u_int16_t port; unsigned int ret; struct ip_conntrack *master = master_ct(ct); IP_NF_ASSERT(info); IP_NF_ASSERT(master); IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum)))); DEBUGP("ip_nat_talk_expected: We have a connection!\n"); LOCK_BH(&ip_talk_lock); port = ct->master->help.exp_talk_info.port; UNLOCK_BH(&ip_talk_lock); DEBUGP("ip_nat_talk_expected: dir %s at hook %s, ct %p, master %p\n", CTINFO2DIR((*pskb)->nfct - ct->infos) == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", ct, master); if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == IPPROTO_UDP) { /* Callee client -> caller server */ #ifdef IP_NAT_TALK_DEBUG struct iphdr *iph = (*pskb)->nh.iph; struct udphdr *udph = (void *)iph + iph->ihl * 4; DEBUGP("ip_nat_talk_expected: UDP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", NIPQUAD(iph->saddr), ntohs(udph->source), NIPQUAD(iph->daddr), ntohs(udph->dest)); #endif newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; DEBUGP("ip_nat_talk_expected: callee client -> caller server, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); } else { /* Callee client -> caller client */ #ifdef IP_NAT_TALK_DEBUG struct iphdr *iph = (*pskb)->nh.iph; struct tcphdr *tcph = (void *)iph + iph->ihl * 4; DEBUGP("ip_nat_talk_expected: TCP %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest)); #endif newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; DEBUGP("ip_nat_talk_expected: callee client -> caller client, newsrc: %u.%u.%u.%u, newdst: %u.%u.%u.%u\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); } if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) newip = newsrcip; else newip = newdstip; DEBUGP("ip_nat_talk_expected: IP to %u.%u.%u.%u, port %u\n", NIPQUAD(newip), ntohs(port)); mr.rangesize = 1; /* We don't want to manip the per-protocol, just the IPs... */ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; mr.range[0].min_ip = mr.range[0].max_ip = newip; /* ... unless we're doing a MANIP_DST, in which case, make sure we map to the correct port */ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].min = mr.range[0].max = ((union ip_conntrack_manip_proto) { .udp = { port } });
/* 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 ip_inbound_pptp_tcp(const struct iphdr *iph, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct pptp_pkt_hdr *pptph; struct PptpControlHeader *ctlh; union { void *rawreq; struct PptpOutCallRequest *ocreq; struct PptpOutCallReply *ocack; struct PptpInCallRequest *icreq; struct PptpInCallReply *icack; struct PptpClearCallRequest *clrreq; struct PptpCallDisconnectNotify *disc; struct PptpWanErrorNotify *wanerr; struct PptpSetLinkInfo *setlink; } pptpReq; __u16 msg, *cid, *pcid; int dir = CTINFO2DIR(ctinfo); pptph = (struct pptp_pkt_hdr *) ((char *) iph + sizeof(struct iphdr) + sizeof(struct tcphdr)); DEBUGP("inbound_pptp_tcp(): CT=%lx, ", (unsigned long) ct); PRINTK_PPTP_HDR("", iph, pptph); ctlh = (struct PptpControlHeader *) ((char *) pptph + sizeof(struct pptp_pkt_hdr)); pptpReq.rawreq = (void *) ((char*) ctlh + sizeof(struct PptpControlHeader)); switch (msg = htons(ctlh->messageType)) { case PPTP_OUT_CALL_REPLY: /* server responding to masq'd client */ cid = &pptpReq.ocack->callID; pcid = &pptpReq.ocack->peersCallID; break; case PPTP_IN_CALL_REPLY: /* server responding to masq'd client */ cid = &pptpReq.icack->callID; pcid = &pptpReq.icack->peersCallID; break; case PPTP_WAN_ERROR_NOTIFY: /* server notifying masq'd client */ /* no need to alter conntrack */ return 0; case PPTP_SET_LINK_INFO: /* server notifying masq'd client */ /* no need to alter conntrack */ return 0; case PPTP_CALL_DISCONNECT_NOTIFY: /* server notifying masq'd client */ /* expire this connection */ ip_ct_refresh(ct, (30*HZ)); clear_gre_tuples(ct); return 0; default: DEBUGP("UNKNOWN inbound packet: "); DEBUGP("%s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? strMName[msg] : strMName[0], msg); /* fall through */ case PPTP_ECHO_REPLY: case PPTP_START_SESSION_REQUEST: case PPTP_START_SESSION_REPLY: case PPTP_STOP_SESSION_REQUEST: case PPTP_STOP_SESSION_REPLY: case PPTP_ECHO_REQUEST: /* no need to alter conntrack */ return 0; } LOCK_BH(&ip_pptp_lock); /* info for conntrack/NAT */ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; struct ip_conntrack_expect expect, *exp = &expect; struct ip_ct_pptp_expect *exp_pptp_info = &exp->help.exp_pptp_info; exp_pptp_info->pptp_magic = PPTP_TCP_PORT; /* our magic number */ exp_pptp_info->orig_call_id = *cid; exp_pptp_info->peer_call_id = *pcid; INIT_LIST_HEAD(&(ct_pptp_info->list)); /* tuple for GRE packets (from server to masqed client) * Here src = pptp server, dst = ppp addr * !dir: src = masq client, dst = pptp server */ /* * masq client <--> pptp serv * new connection replaces any old ones. */ /* * populate our lists for peer call ID lookup */ put_gre_tuple(ct->tuplehash[!dir].tuple.src.ip, ct->tuplehash[!dir].tuple.dst.ip, *cid, *pcid, ct); put_gre_tuple(ct->tuplehash[!dir].tuple.dst.ip, ct->tuplehash[!dir].tuple.src.ip, *pcid, *cid, ct); put_gre_tuple(ct->tuplehash[dir].tuple.src.ip, ct->tuplehash[dir].tuple.dst.ip, *pcid, *cid, ct); put_gre_tuple(ct->tuplehash[dir].tuple.dst.ip, ct->tuplehash[dir].tuple.src.ip, *cid, *pcid, ct); if(ip_conntrack_protocol_register(&ip_conntrack_protocol_gre) == 0) DEBUGP("pptp: registered conntrack protocol GRE!\n"); else DEBUGP("pptp: failed to register conntrack protocol GRE!\n"); UNLOCK_BH(&ip_pptp_lock); return 0; }
static void ipt_ulog_packet(unsigned int hooknum, const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct ipt_ulog_info *loginfo, const char *prefix) { ulog_buff_t *ub; ulog_packet_msg_t *pm; size_t size, copy_len; struct nlmsghdr *nlh; /* ffs == find first bit set, necessary because userspace * is already shifting groupnumber, but we need unshifted. * ffs() returns [1..32], we need [0..31] */ unsigned int groupnum = ffs(loginfo->nl_group) - 1; /* calculate the size of the skb needed */ if ((loginfo->copy_range == 0) || (loginfo->copy_range > skb->len)) { copy_len = skb->len; } else { copy_len = loginfo->copy_range; } size = NLMSG_SPACE(sizeof(*pm) + copy_len); ub = &ulog_buffers[groupnum]; LOCK_BH(&ulog_lock); if (!ub->skb) { if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } else if (ub->qlen >= loginfo->qthreshold || size > skb_tailroom(ub->skb)) { /* either the queue len is too high or we don't have * enough room in nlskb left. send it to userspace. */ ulog_send(groupnum); if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, loginfo->qthreshold); /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, sizeof(*pm)+copy_len); ub->qlen++; pm = NLMSG_DATA(nlh); /* We might not have a timestamp, get one */ if (skb->stamp.tv_sec == 0) do_gettimeofday((struct timeval *)&skb->stamp); /* copy hook, prefix, timestamp, payload, etc. */ pm->data_len = copy_len; pm->timestamp_sec = skb->stamp.tv_sec; pm->timestamp_usec = skb->stamp.tv_usec; pm->mark = skb->nfmark; pm->hook = hooknum; if (prefix != NULL) strncpy(pm->prefix, prefix, sizeof(pm->prefix)); else if (loginfo->prefix[0] != '\0') strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); else *(pm->prefix) = '\0'; if (in && in->hard_header_len > 0 && skb->mac.raw != (void *) skb->nh.iph && in->hard_header_len <= ULOG_MAC_LEN) { memcpy(pm->mac, skb->mac.raw, in->hard_header_len); pm->mac_len = in->hard_header_len; } else pm->mac_len = 0; if (in) strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); else pm->indev_name[0] = '\0'; if (out) strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); else pm->outdev_name[0] = '\0'; /* copy_len <= skb->len, so can't fail. */ if (skb_copy_bits(skb, 0, pm->payload, copy_len) < 0) BUG(); /* check if we are building multi-part messages */ if (ub->qlen > 1) { ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; } ub->lastnlh = nlh; /* if timer isn't already running, start it */ if (!timer_pending(&ub->timer)) { ub->timer.expires = jiffies + flushtimeout * HZ / 100; add_timer(&ub->timer); } /* if threshold is reached, send message to userspace */ if (ub->qlen >= loginfo->qthreshold) { if (loginfo->qthreshold > 1) nlh->nlmsg_type = NLMSG_DONE; ulog_send(groupnum); } UNLOCK_BH(&ulog_lock); return; nlmsg_failure: PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); alloc_failure: PRINTR("ipt_ULOG: Error building netlink message\n"); UNLOCK_BH(&ulog_lock); }
/* FIXME: This should be in userspace. Later. */ static int help(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { int ret = NF_DROP; struct tcphdr _tcph, *th; char *data, *mb_ptr; unsigned int datalen, dataoff; //struct tcphdr *tcph = (void *)iph + iph->ihl * 4; //unsigned int tcplen = len - iph->ihl * 4; //unsigned int datalen = tcplen - tcph->doff * 4; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect *exp; struct ip_ct_mms_expect _emmi, *exp_mms_info = &_emmi; u_int32_t mms_ip; u_int16_t mms_proto; char mms_proto_string[8]; u_int16_t mms_port; char *mms_string_b, *mms_string_e, *mms_padding_e; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } /* Not whole TCP header? */ th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, sizeof(_tcph), &_tcph); if (!th) return NF_ACCEPT; /* No data ? */ dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4; datalen = (*pskb)->len - dataoff; if (dataoff >= (*pskb)->len) return NF_ACCEPT; LOCK_BH(&mms_buffer_lock); mb_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, mms_buffer); BUG_ON(mb_ptr == NULL); data = mb_ptr; #if 0 /* Checksum invalid? Ignore. */ /* FIXME: Source route IP option packets --RR */ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *)tcph, tcplen, 0))) { DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); return NF_ACCEPT; } #endif /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP * payload */ /* FIXME: There is an issue with only looking at this packet: before * this packet, the client has already sent a packet to the server with * the server's hostname according to the client (think of it as the * "Host: " header in HTTP/1.1). The server will break the connection * if this doesn't correspond to its own host header. The client can * also connect to an IP address; if it's the server's IP address, it * will not break the connection. When doing DNAT on a connection where * the client uses a server's IP address, the nat module should detect * this and change this string accordingly to the DNATed address. This * should probably be done by checking for an IP address, then storing * it as a member of struct ip_ct_mms_expect and checking for it in * ip_nat_mms... */ if ((MMS_SRV_MSG_OFFSET < datalen) && ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) { DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", (u8)*(data+36), (u8)*(data+37), (u8)*(data+38), (u8)*(data+39), datalen); if (parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port, &mms_string_b, &mms_string_e, &mms_padding_e)) if (net_ratelimit()) /* FIXME: more verbose debugging ? */ printk(KERN_WARNING "ip_conntrack_mms: Unable to parse " "data payload\n"); sprintf(mms_proto_string, "(%u)", mms_proto); DEBUGP("ip_conntrack_mms: adding %s expectation " "%u.%u.%u.%u -> %u.%u.%u.%u:%u\n", mms_proto == IPPROTO_TCP ? "TCP" : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string, NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), NIPQUAD(mms_ip), mms_port); /* it's possible that the client will just ask the server to * tunnel the stream over the same TCP session (from port * 1755): there's shouldn't be a need to add an expectation in * that case, but it makes NAT packet mangling so much easier * */ DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq); exp = ip_conntrack_expect_alloc(); if (!exp) { ret = NF_DROP; goto out; } exp_mms_info->offset = (mms_string_b - data); exp_mms_info->len = (mms_string_e - mms_string_b); exp_mms_info->padding = (mms_padding_e - mms_string_e); exp_mms_info->port = mms_port; DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), " "len=%d, padding=%u\n", exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding); exp->tuple = ((struct ip_conntrack_tuple) { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, { mms_ip,
static unsigned int help(struct ip_conntrack *ct, struct ip_conntrack_expect *exp, struct ip_nat_info *info, enum ip_conntrack_info ctinfo, unsigned int hooknum, struct sk_buff **pskb) { struct iphdr *iph = (*pskb)->nh.iph; struct tcphdr *tcph = (void *)iph + iph->ihl*4; unsigned int datalen; int dir; int score; struct ip_ct_sc_expect *exp_sc_info = &exp->help.exp_sc_info; /* Only mangle things once: original direction in POST_ROUTING and reply direction on PRE_ROUTING. */ dir = CTINFO2DIR(ctinfo); DEBUGP("nat_sc: help()\n"); #if 0 if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_REPLY) || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_ORIGINAL))) { #if 1 DEBUGP("nat_sc: 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" : "???"); #endif return NF_ACCEPT; } #endif datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; score = 0; LOCK_BH(&ip_sc_lock); if (exp_sc_info->len) { /* If it's in the right range... */ score += between(exp_sc_info->seq, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); score += between(exp_sc_info->seq + exp_sc_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); if (score == 1) { /* Half a match? This means a partial retransmisison. It's a cracker being funky. */ if (net_ratelimit()) { printk("SC_NAT: partial packet %u/%u in %u/%u\n", exp_sc_info->seq, exp_sc_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); } UNLOCK_BH(&ip_sc_lock); return NF_DROP; } else if (score == 2) { if (!sc_data_fixup(exp_sc_info, ct, datalen, pskb, ctinfo)) { UNLOCK_BH(&ip_sc_lock); return NF_DROP; } /* skb may have been reallocated */ iph = (*pskb)->nh.iph; tcph = (void *)iph + iph->ihl*4; } } UNLOCK_BH(&ip_sc_lock); DEBUGP("nat_sc: ip_nat_seq_adjust()\n"); ip_nat_seq_adjust(*pskb, ct, ctinfo); return NF_ACCEPT; }
/* FIXME: This should be in userspace. Later. */ static int h245_help(const struct iphdr *iph, size_t len, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct tcphdr *tcph = (void *)iph + iph->ihl * 4; unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; unsigned char *data_limit; u_int32_t tcplen = len - iph->ihl * 4; u_int32_t datalen = tcplen - tcph->doff * 4; int dir = CTINFO2DIR(ctinfo); struct ip_ct_h225_master *info = &ct->help.ct_h225_info; struct ip_conntrack_expect expect, *exp = &expect; struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; u_int16_t data_port; u_int32_t data_ip; unsigned int i; DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", NIPQUAD(iph->saddr), ntohs(tcph->source), NIPQUAD(iph->daddr), ntohs(tcph->dest)); #ifdef CONFIG_IFX_ALG_QOS //Suresh ct->ifx_alg_qos_mark = IFX_ALG_APP_H323; DEBUGP ("\nH323_ALG h245_help marked ct->ifx_alg_qos_mark to : %x ***\n", ct->ifx_alg_qos_mark ); #endif /* Can't track connections formed before we registered */ if (!info) return NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } /* Not whole TCP header or too short packet? */ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen); return NF_ACCEPT; } /* Checksum invalid? Ignore. */ /* FIXME: Source route IP option packets --RR */ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *)tcph, tcplen, 0))) { DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); return NF_ACCEPT; } data_limit = (unsigned char *) data + datalen; /* bytes: 0123 45 ipadrr port */ for (i = 0; data < (data_limit - 5); data++, i++) { data_ip = *((u_int32_t *)data); if (data_ip == iph->saddr) { data_port = *((u_int16_t *)(data + 4)); memset(&expect, 0, sizeof(expect)); /* update the H.225 info */ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), NIPQUAD(iph->saddr), ntohs(data_port)); LOCK_BH(&ip_h323_lock); info->is_h225 = H225_PORT + 1; exp_info->port = data_port; exp_info->dir = dir; exp_info->offset = i; exp->seq = ntohl(tcph->seq) + i; exp->tuple = ((struct ip_conntrack_tuple) { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, { data_ip, { .udp = { .port = data_port } }, IPPROTO_UDP }});
/* FIXME: This should be in userspace. Later. */ static int help(const struct iphdr *iph, size_t len, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { /* tcplen not negative guaranteed by ip_conntrack_tcp.c */ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; const char *data = (const char *)tcph + tcph->doff * 4; unsigned int tcplen = len - iph->ihl * 4; unsigned int datalen = tcplen - tcph->doff * 4; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect expect, *exp = &expect; struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info; u_int32_t mms_ip; u_int16_t mms_proto; char mms_proto_string[8]; u_int16_t mms_port; char *mms_string_b, *mms_string_e, *mms_padding_e; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } /* Not whole TCP header? */ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) { DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen); return NF_ACCEPT; } /* Checksum invalid? Ignore. */ /* FIXME: Source route IP option packets --RR */ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *)tcph, tcplen, 0))) { DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); return NF_ACCEPT; } /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */ /* FIXME: There is an issue with only looking at this packet: before this packet, the client has already sent a packet to the server with the server's hostname according to the client (think of it as the "Host: " header in HTTP/1.1). The server will break the connection if this doesn't correspond to its own host header. The client can also connect to an IP address; if it's the server's IP address, it will not break the connection. When doing DNAT on a connection where the client uses a server's IP address, the nat module should detect this and change this string accordingly to the DNATed address. This should probably be done by checking for an IP address, then storing it as a member of struct ip_ct_mms_expect and checking for it in ip_nat_mms... */ if( (MMS_SRV_MSG_OFFSET < datalen) && ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) { DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", (u8)*(data+36), (u8)*(data+37), (u8)*(data+38), (u8)*(data+39), datalen); if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port, &mms_string_b, &mms_string_e, &mms_padding_e)) if(net_ratelimit()) /* FIXME: more verbose debugging ? */ printk(KERN_WARNING "ip_conntrack_mms: Unable to parse data payload\n"); memset(&expect, 0, sizeof(expect)); sprintf(mms_proto_string, "(%u)", mms_proto); DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n", mms_proto == IPPROTO_TCP ? "TCP" : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string, NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), NIPQUAD(mms_ip), mms_port); /* it's possible that the client will just ask the server to tunnel the stream over the same TCP session (from port 1755): there's shouldn't be a need to add an expectation in that case, but it makes NAT packet mangling so much easier */ LOCK_BH(&ip_mms_lock); DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq); exp->seq = ntohl(tcph->seq) + (mms_string_b - data); exp_mms_info->len = (mms_string_e - mms_string_b); exp_mms_info->padding = (mms_padding_e - mms_string_e); exp_mms_info->port = mms_port; DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n", exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding); exp->tuple = ((struct ip_conntrack_tuple) { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, { mms_ip,
static int help(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct ip_conntrack_expect *exp; struct ip_ct_amanda_expect *exp_amanda_info; char *data, *data_limit, *tmp; unsigned int dataoff, i; u_int16_t port, len; /* Only look at packets from the Amanda server */ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) return NF_ACCEPT; /* increase the UDP timeout of the master connection as replies from * Amanda clients to the server can be quite delayed */ ip_ct_refresh(ct, master_timeout * HZ); /* No data? */ dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr); if (dataoff >= skb->len) { if (net_ratelimit()) printk("amanda_help: skblen = %u\n", skb->len); return NF_ACCEPT; } LOCK_BH(&amanda_buffer_lock); skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff); data = amanda_buffer; data_limit = amanda_buffer + skb->len - dataoff; *data_limit = '\0'; /* Search for the CONNECT string */ data = strstr(data, "CONNECT "); if (!data) goto out; data += strlen("CONNECT "); /* Only search first line. */ if ((tmp = strchr(data, '\n'))) *tmp = '\0'; for (i = 0; i < ARRAY_SIZE(conns); i++) { char *match = strstr(data, conns[i]); if (!match) continue; tmp = data = match + strlen(conns[i]); port = simple_strtoul(data, &data, 10); len = data - tmp; if (port == 0 || len > 5) break; exp = ip_conntrack_expect_alloc(); if (exp == NULL) goto out; exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; exp->tuple.dst.protonum = IPPROTO_TCP; exp->mask.src.ip = 0xFFFFFFFF; exp->mask.dst.ip = 0xFFFFFFFF; exp->mask.dst.protonum = 0xFFFF; exp->mask.dst.u.tcp.port = 0xFFFF; exp_amanda_info = &exp->help.exp_amanda_info; exp_amanda_info->offset = data - amanda_buffer; exp_amanda_info->port = port; exp_amanda_info->len = len; exp->tuple.dst.u.tcp.port = htons(port); ip_conntrack_expect_related(exp, ct); } out: UNLOCK_BH(&amanda_buffer_lock); return NF_ACCEPT; }
static int help(struct sk_buff *skb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { char *data, *data_limit; int dir = CTINFO2DIR(ctinfo); unsigned int dataoff, i; struct ip_ct_amanda *info = (struct ip_ct_amanda *)&ct->help.ct_ftp_info; /* Can't track connections formed before we registered */ if (!info) return NF_ACCEPT; /* increase the UDP timeout of the master connection as replies from * Amanda clients to the server can be quite delayed */ ip_ct_refresh(ct, master_timeout * HZ); /* If packet is coming from Amanda server */ if (dir == IP_CT_DIR_ORIGINAL) return NF_ACCEPT; /* No data? */ dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr); if (dataoff >= skb->len) { if (net_ratelimit()) printk("ip_conntrack_amanda_help: skblen = %u\n", (unsigned)skb->len); return NF_ACCEPT; } LOCK_BH(&ip_amanda_lock); skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff); data = amanda_buffer; data_limit = amanda_buffer + skb->len - dataoff; *data_limit = '\0'; /* Search for the CONNECT string */ data = strstr(data, "CONNECT "); if (!data) goto out; DEBUGP("ip_conntrack_amanda_help: CONNECT found in connection " "%u.%u.%u.%u:%u %u.%u.%u.%u:%u\n", NIPQUAD(iph->saddr), htons(udph->source), NIPQUAD(iph->daddr), htons(udph->dest)); data += strlen("CONNECT "); /* Only search first line. */ if (strchr(data, '\n')) *strchr(data, '\n') = '\0'; for (i = 0; i < ARRAY_SIZE(conns); i++) { char *match = strstr(data, conns[i]); if (match) { char *portchr; struct ip_conntrack_expect expect; struct ip_ct_amanda_expect *exp_amanda_info = &expect.help.exp_amanda_info; memset(&expect, 0, sizeof(expect)); data += strlen(conns[i]); /* this is not really tcp, but let's steal an * idea from a tcp stream helper :-) */ // XXX expect.seq = data - amanda_buffer; exp_amanda_info->offset = data - amanda_buffer; // XXX DEBUGP("expect.seq = %p - %p = %d\n", data, amanda_buffer, expect.seq); DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, amanda_buffer, exp_amanda_info->offset); portchr = data; exp_amanda_info->port = simple_strtoul(data, &data,10); exp_amanda_info->len = data - portchr; /* eat whitespace */ while (*data == ' ') data++; DEBUGP("ip_conntrack_amanda_help: " "CONNECT %s request with port " "%u found\n", conns[i], exp_amanda_info->port); expect.tuple = ((struct ip_conntrack_tuple) { { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, { 0 } }, { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, { htons(exp_amanda_info->port) }, IPPROTO_TCP }});
/* track caller id inside control connection, call expect_related */ static int conntrack_pptp_help(const struct iphdr *iph, size_t len, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct pptp_pkt_hdr *pptph; struct tcphdr *tcph = (void *) iph + iph->ihl * 4; u_int32_t tcplen = len - iph->ihl * 4; u_int32_t datalen = tcplen - tcph->doff * 4; void *datalimit; int dir = CTINFO2DIR(ctinfo); struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; int oldsstate, oldcstate; int ret; #ifdef CONFIG_IFX_ALG_QOS // chandrav /* * Mark the connection tracket with PPTP ALG Family type * ( IFX_ALG_APP_PPTP) for PPTP traffic. */ ct->ifx_alg_qos_mark = IFX_ALG_APP_PPTP; IFX_ALG_QOS_DBG("\nPPTP_ALG helper marked ct->ifx_alg_qos_mark to : %x ***\n",ct->ifx_alg_qos_mark ); #endif /* CONFIG_IFX_ALG_QOS */ /* don't do any tracking before tcp handshake complete */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { DEBUGP("ctinfo = %u, skipping\n", ctinfo); return NF_ACCEPT; } /* not a complete TCP header? */ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { DEBUGP("tcplen = %u\n", tcplen); return NF_ACCEPT; } /* checksum invalid? */ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *) tcph, tcplen, 0))) { DEBUGP("TC Test0\n"); printk(KERN_NOTICE __FILE__ ": bad csum\n"); /* W2K PPTP server sends TCP packets with wrong checksum :(( */ //return NF_ACCEPT; } DEBUGP("TC Test1\n"); if (tcph->fin || tcph->rst) { DEBUGP("RST/FIN received, timeouting GRE\n"); /* can't do this after real newnat */ info->cstate = PPTP_CALL_NONE; /* untrack this call id, unexpect GRE packets */ pptp_timeout_related(ct); } DEBUGP("TC Test2\n"); pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4); datalimit = (void *) pptph + datalen; /* not a full pptp packet header? */ if ((void *) pptph+sizeof(*pptph) >= datalimit) { DEBUGP("no full PPTP header, can't track\n"); return NF_ACCEPT; } /* if it's not a control message we can't do anything with it */ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { DEBUGP("not a control packet\n"); return NF_ACCEPT; } DEBUGP("TC Test3\n"); oldsstate = info->sstate; oldcstate = info->cstate; LOCK_BH(&ip_pptp_lock); /* FIXME: We just blindly assume that the control connection is always * established from PNS->PAC. However, RFC makes no guarantee */ if (dir == IP_CT_DIR_ORIGINAL) /* client -> server (PNS -> PAC) */ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); else /* server -> client (PAC -> PNS) */ ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo); DEBUGP("sstate: %d->%d, cstate: %d->%d\n", oldsstate, info->sstate, oldcstate, info->cstate); UNLOCK_BH(&ip_pptp_lock); return ret; }
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 }});
static unsigned int ipt_ulog_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo) { ulog_buff_t *ub; ulog_packet_msg_t *pm; size_t size, copy_len; struct nlmsghdr *nlh; struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo; /* calculate the size of the skb needed */ if ((loginfo->copy_range == 0) || (loginfo->copy_range > (*pskb)->len)) { copy_len = (*pskb)->len; } else { copy_len = loginfo->copy_range; } size = NLMSG_SPACE(sizeof(*pm) + copy_len); ub = &ulog_buffers[loginfo->nl_group]; LOCK_BH(&ulog_lock); if (!ub->skb) { if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } else if (ub->qlen >= loginfo->qthreshold || size > skb_tailroom(ub->skb)) { /* either the queue len is too high or we don't have * enough room in nlskb left. send it to userspace. */ ulog_send(loginfo->nl_group); if (!(ub->skb = ulog_alloc_skb(size))) goto alloc_failure; } DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen, loginfo->qthreshold); /* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */ nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT, size - sizeof(*nlh)); ub->qlen++; pm = NLMSG_DATA(nlh); /* copy hook, prefix, timestamp, payload, etc. */ pm->data_len = copy_len; pm->timestamp_sec = (*pskb)->stamp.tv_sec; pm->timestamp_usec = (*pskb)->stamp.tv_usec; pm->mark = (*pskb)->nfmark; pm->hook = hooknum; if (loginfo->prefix[0] != '\0') strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); else *(pm->prefix) = '\0'; if (in && in->hard_header_len > 0 && (*pskb)->mac.raw != (void *) (*pskb)->nh.iph && in->hard_header_len <= ULOG_MAC_LEN) { memcpy(pm->mac, (*pskb)->mac.raw, in->hard_header_len); pm->mac_len = in->hard_header_len; } if (in) strncpy(pm->indev_name, in->name, sizeof(pm->indev_name)); else pm->indev_name[0] = '\0'; if (out) strncpy(pm->outdev_name, out->name, sizeof(pm->outdev_name)); else pm->outdev_name[0] = '\0'; if (copy_len) memcpy(pm->payload, (*pskb)->data, copy_len); /* check if we are building multi-part messages */ if (ub->qlen > 1) { ub->lastnlh->nlmsg_flags |= NLM_F_MULTI; } /* if threshold is reached, send message to userspace */ if (qlen >= loginfo->qthreshold) { if (loginfo->qthreshold > 1) nlh->nlmsg_type = NLMSG_DONE; } ub->lastnlh = nlh; /* if timer isn't already running, start it */ if (!timer_pending(&ub->timer)) { ub->timer.expires = jiffies + flushtimeout; add_timer(&ub->timer); } UNLOCK_BH(&ulog_lock); return IPT_CONTINUE; nlmsg_failure: PRINTR("ipt_ULOG: error during NLMSG_PUT\n"); alloc_failure: PRINTR("ipt_ULOG: Error building netlink message\n"); UNLOCK_BH(&ulog_lock); return IPT_CONTINUE; }
static unsigned int h225_nat_expected(struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, struct ip_nat_info *info) { struct ip_nat_multi_range mr; u_int32_t newdstip, newsrcip, newip; u_int16_t port; struct ip_ct_h225_expect *exp_info; struct ip_ct_h225_master *master_info; struct ip_conntrack *master = master_ct(ct); unsigned int is_h225, ret; IP_NF_ASSERT(info); IP_NF_ASSERT(master); IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum)))); DEBUGP("h225_nat_expected: We have a connection!\n"); master_info = &ct->master->expectant->help.ct_h225_info; exp_info = &ct->master->help.exp_h225_info; LOCK_BH(&ip_h323_lock); DEBUGP("master: "); DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); DEBUGP("conntrack: "); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); if (exp_info->dir == IP_CT_DIR_ORIGINAL) { /* Make connection go to the client. */ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); } else { /* Make the connection go to the server */ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", NIPQUAD(newsrcip), NIPQUAD(newdstip)); } port = exp_info->port; is_h225 = master_info->is_h225 == H225_PORT; UNLOCK_BH(&ip_h323_lock); if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) newip = newsrcip; else newip = newdstip; DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); mr.rangesize = 1; /* We don't want to manip the per-protocol, just the IPs... */ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; mr.range[0].min_ip = mr.range[0].max_ip = newip; /* ... unless we're doing a MANIP_DST, in which case, make sure we map to the correct port */ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].min = mr.range[0].max = ((union ip_conntrack_manip_proto) { .tcp = { port } });
static int quake3_help(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct udphdr _udph, *uh; struct ip_conntrack_expect *exp; void *data, *qb_ptr; int dir = CTINFO2DIR(ctinfo); int i, dataoff; int ret = NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. note: * it's UDP ! */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_IS_REPLY) { DEBUGP("ip_conntrack_quake3: not ok ! Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } else { DEBUGP("ip_conntrack_quake3: it's ok ! Conntrackinfo = %u\n", ctinfo); } /* Valid UDP header? */ uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4, sizeof(_udph), &_udph); if (!uh) return NF_ACCEPT; /* Any data? */ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); if (dataoff >= (*pskb)->len) return NF_ACCEPT; LOCK_BH(&quake3_buffer_lock); qb_ptr = skb_header_pointer(*pskb, dataoff, (*pskb)->len - dataoff, quake3_buffer); BUG_ON(qb_ptr == NULL); data = qb_ptr; if (strnicmp(data + 4, quake3s_conntrack.pattern, quake3s_conntrack.plen) == 0) { for(i=23; /* 4 bytes filler, 18 bytes "getserversResponse", 1 byte "\" */ i+6 < ntohs(uh->len); i+=7) { u_int32_t *ip = data+i; u_int16_t *port = data+i+4; #if 0 DEBUGP("ip_conntrack_quake3: adding server at offset " "%u/%u %u.%u.%u.%u:%u\n", i, ntohs(uh->len), NIPQUAD(*ip), ntohs(*port)); #endif exp = ip_conntrack_expect_alloc(); if (!exp) { ret = NF_DROP; goto out; } memset(exp, 0, sizeof(*exp)); exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; exp->tuple.dst.ip = *ip; exp->tuple.dst.u.udp.port = *port; exp->tuple.dst.protonum = IPPROTO_UDP; exp->mask.src.ip = 0xffffffff; exp->mask.dst.ip = 0xffffffff; exp->mask.dst.u.udp.port = 0xffff; exp->mask.dst.protonum = 0xff; if (ip_nat_quake3_hook) ret = ip_nat_quake3_hook(exp); else if (ip_conntrack_expect_related(exp) != 0) { ip_conntrack_expect_free(exp); ret = NF_DROP; } goto out; } } out: 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; u_int32_t tcplen = len - iph->ihl * 4; int dir = CTINFO2DIR(ctinfo); struct ip_conntrack_expect expect, *exp = &expect; struct ip_ct_rsh_expect *exp_rsh_info = &exp->help.exp_rsh_info; u_int16_t port; int maxoctet; /* note that "maxoctet" is used to maintain sanity (8 was the * original array size used in rshd/glibc) -- is there a * vulnerability in rshd.c in the looped port *= 10? */ DEBUGP("entered\n"); /* bail if packet is not from RSH client */ if (dir == IP_CT_DIR_REPLY) return NF_ACCEPT; /* Until there's been traffic both ways, don't look in packets. */ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { DEBUGP("Conntrackinfo = %u\n", ctinfo); return NF_ACCEPT; } /* Not whole TCP header? */ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { DEBUGP("tcplen = %u\n", (unsigned) tcplen); return NF_ACCEPT; } /* Checksum invalid? Ignore. */ /* FIXME: Source route IP option packets --RR */ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, csum_partial((char *) tcph, tcplen, 0))) { DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); return NF_ACCEPT; } /* find the rsh stderr port */ maxoctet = 4; port = 0; for ( ; *data != 0 && maxoctet != 0; data++, maxoctet--) { if (*data < 0) return(1); if (*data == 0) break; if (*data < 48 || *data > 57) { DEBUGP("these aren't the packets you're looking for ..\n"); return NF_ACCEPT; } port = port * 10 + ( *data - 48 ); } /* dont relate sessions that try to expose the client */ DEBUGP("found port %u\n", port); if (port > range) { DEBUGP("skipping, expected port size is greater than range!\n"); return NF_ACCEPT; } LOCK_BH(&ip_rsh_lock); /* new(,related) connection is; * reply + dst (uint)port + src port (0:1023) */ memset(&expect, 0, sizeof(expect)); /* save some discovered data, in case someone ever wants to write * a NAT module for this bastard .. */ exp_rsh_info->port = port; DEBUGP("wrote info port=%u\n", exp_rsh_info->port); /* Watch out, Radioactive-Man! */ exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.src.u.tcp.port = 0; exp->tuple.dst.u.tcp.port = htons(exp_rsh_info->port); exp->tuple.dst.protonum = IPPROTO_TCP; exp->mask.src.ip = 0xffffffff; exp->mask.dst.ip = 0xffffffff; exp->mask.src.u.tcp.port = htons(rangemask); exp->mask.dst.u.tcp.port = htons(0xffff); exp->mask.dst.protonum = 0xffff; exp->expectfn = NULL; ip_conntrack_expect_related(ct, &expect); DEBUGP("expect related ip %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); DEBUGP("expect related mask %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", NIPQUAD(exp->mask.src.ip), ntohs(exp->mask.src.u.tcp.port), NIPQUAD(exp->mask.dst.ip), ntohs(exp->mask.dst.u.tcp.port)); UNLOCK_BH(&ip_rsh_lock); return NF_ACCEPT; }