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 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 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 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; }
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; }
/* 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 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); }
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 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 } });
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; }
/* 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; }