static unsigned int ipv4_conntrack_help(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; struct nf_conn_help *help; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(*pskb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) return NF_ACCEPT; help = nfct_help(ct); if (!help || !help->helper) return NF_ACCEPT; #if defined(CONFIG_RA_HW_NAT) || defined(CONFIG_RA_HW_NAT_MODULE) if( (skb_headroom(*pskb) >=4) && ((FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_PCI) || (FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_WLAN) || (FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_GE))){ FOE_ALG_RXIF(*pskb)=1; } #endif return help->helper->help(pskb, (*pskb)->nh.raw - (*pskb)->data + (*pskb)->nh.iph->ihl*4, ct, ctinfo); }
/* timeout GRE data connections */ static void pptp_destroy_siblings(struct nf_conn *ct) { struct net *net = nf_ct_net(ct); const struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_tuple t; #ifdef CONFIG_HTC_NET_MODIFY if (help == NULL) printk("[NET] help = NULL in %s\n", __func__); #endif nf_ct_gre_keymap_destroy(ct); /* try original (pns->pac) tuple */ memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); t.dst.protonum = IPPROTO_GRE; t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id; t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id; if (!destroy_sibling_or_exp(net, ct, &t)) pr_debug("failed to timeout original pns->pac ct/exp\n"); /* try reply (pac->pns) tuple */ memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); t.dst.protonum = IPPROTO_GRE; t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id; t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id; if (!destroy_sibling_or_exp(net, ct, &t)) pr_debug("failed to timeout reply pac->pns ct/exp\n"); }
static unsigned int ipv4_helper(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED_REPLY) return NF_ACCEPT; help = nfct_help(ct); if (!help) return NF_ACCEPT; /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) return NF_ACCEPT; return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo); }
static int process_urq(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, UnregistrationRequest *urq) { struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int ret; typeof(set_sig_addr_hook) set_sig_addr; pr_debug("nf_ct_ras: URQ\n"); set_sig_addr = rcu_dereference(set_sig_addr_hook); if (set_sig_addr && ct->status & IPS_NAT_MASK) { ret = set_sig_addr(skb, ct, ctinfo, data, urq->callSignalAddress.item, urq->callSignalAddress.count); if (ret < 0) return -1; } nf_ct_remove_expectations(ct); info->sig_port[dir] = 0; info->sig_port[!dir] = 0; nf_ct_refresh(ct, skb, 30 * HZ); return 0; }
static bool helper_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_helper_info *info = par->matchinfo; const struct nf_conn *ct; const struct nf_conn_help *master_help; const struct nf_conntrack_helper *helper; enum ip_conntrack_info ctinfo; bool ret = info->invert; ct = nf_ct_get(skb, &ctinfo); if (!ct || !ct->master) return ret; master_help = nfct_help(ct->master); if (!master_help) return ret; /* */ helper = rcu_dereference(master_help->helper); if (!helper) return ret; if (info->name[0] == '\0') ret = !ret; else ret ^= !strncmp(helper->name, info->name, strlen(helper->name)); return ret; }
static int map_addr(struct sk_buff *skb, unsigned int dataoff, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, union nf_inet_addr *addr, __be16 port) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); #if defined(CONFIG_SYNO_COMCERTO) struct nf_conn_help *help = nfct_help(ct); #endif char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; unsigned int buflen; __be32 newaddr; __be16 newport; if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip && ct->tuplehash[dir].tuple.src.u.udp.port == port) { newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip; newport = ct->tuplehash[!dir].tuple.dst.u.udp.port; } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip && ct->tuplehash[dir].tuple.dst.u.udp.port == port) { newaddr = ct->tuplehash[!dir].tuple.src.u3.ip; #if defined(CONFIG_SYNO_COMCERTO) newport = help->help.ct_sip_info.forced_dport ? : ct->tuplehash[!dir].tuple.src.u.udp.port; #else newport = ct->tuplehash[!dir].tuple.src.u.udp.port; #endif } else
static int process_urq(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, UnregistrationRequest *urq) { struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int ret; typeof(set_sig_addr_hook) set_sig_addr; pr_debug("nf_ct_ras: URQ\n"); #ifdef CONFIG_HTC_NETWORK_MODIFY if (IS_ERR(info) || (!info)) printk(KERN_ERR "[NET] info is NULL in %s!\n", __func__); #endif set_sig_addr = rcu_dereference(set_sig_addr_hook); if (set_sig_addr && ct->status & IPS_NAT_MASK) { ret = set_sig_addr(skb, ct, ctinfo, data, urq->callSignalAddress.item, urq->callSignalAddress.count); if (ret < 0) return -1; } nf_ct_remove_expectations(ct); info->sig_port[dir] = 0; info->sig_port[!dir] = 0; nf_ct_refresh(ct, skb, 30 * HZ); return 0; }
static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) { struct xt_ct_target_info_v1 *info = par->targinfo; struct nf_conn *ct = info->ct; struct nf_conn_help *help; #ifdef CONFIG_NF_CONNTRACK_TIMEOUT struct nf_conn_timeout *timeout_ext; typeof(nf_ct_timeout_put_hook) timeout_put; #endif if (!nf_ct_is_untracked(ct)) { help = nfct_help(ct); if (help) module_put(help->helper->me); nf_ct_l3proto_module_put(par->family); #ifdef CONFIG_NF_CONNTRACK_TIMEOUT rcu_read_lock(); timeout_put = rcu_dereference(nf_ct_timeout_put_hook); if (timeout_put) { timeout_ext = nf_ct_timeout_find(ct); if (timeout_ext) timeout_put(timeout_ext->timeout); } rcu_read_unlock(); #endif } nf_ct_put(info->ct); }
static void pptp_exp_gre(struct nf_conntrack_expect *expect_orig, struct nf_conntrack_expect *expect_reply) { const struct nf_conn *ct = expect_orig->master; struct nf_ct_pptp_master *ct_pptp_info; struct nf_nat_pptp *nat_pptp_info; ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; /* save original PAC call ID in nat_info */ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; /* alter expectation for PNS->PAC direction */ expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; expect_orig->dir = IP_CT_DIR_ORIGINAL; /* alter expectation for PAC->PNS direction */ expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; expect_reply->dir = IP_CT_DIR_REPLY; }
static unsigned int ipv4_helper(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; unsigned int ret; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED_REPLY) return NF_ACCEPT; help = nfct_help(ct); if (!help) return NF_ACCEPT; /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) return NF_ACCEPT; ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo); if (ret != NF_ACCEPT && (ret & NF_VERDICT_MASK) != NF_QUEUE) { nf_log_packet(NFPROTO_IPV4, hooknum, skb, in, out, NULL, "nf_ct_%s: dropping packet", helper->name); } return ret; }
static void pptp_exp_gre(struct nf_conntrack_expect *expect_orig, struct nf_conntrack_expect *expect_reply) { const struct nf_conn *ct = expect_orig->master; struct nf_ct_pptp_master *ct_pptp_info; struct nf_nat_pptp *nat_pptp_info; ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; expect_orig->dir = IP_CT_DIR_ORIGINAL; expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; expect_reply->dir = IP_CT_DIR_REPLY; }
static inline int ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) { struct nfattr *nest_helper; const struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_helper *helper; if (!help) return 0; rcu_read_lock(); helper = rcu_dereference(help->helper); if (!helper) goto out; nest_helper = NFA_NEST(skb, CTA_HELP); NFA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); if (helper->to_nfattr) helper->to_nfattr(skb, ct); NFA_NEST_END(skb, nest_helper); out: rcu_read_unlock(); return 0; nfattr_failure: rcu_read_unlock(); return -1; }
static int process_rrq(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, RegistrationRequest *rrq) { struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int ret; typeof(set_ras_addr_hook) set_ras_addr; pr_debug("nf_ct_ras: RRQ\n"); ret = expect_q931(skb, ct, ctinfo, data, rrq->callSignalAddress.item, rrq->callSignalAddress.count); if (ret < 0) return -1; set_ras_addr = rcu_dereference(set_ras_addr_hook); if (set_ras_addr && ct->status & IPS_NAT_MASK) { ret = set_ras_addr(skb, ct, ctinfo, data, rrq->rasAddress.item, rrq->rasAddress.count); if (ret < 0) return -1; } if (rrq->options & eRegistrationRequest_timeToLive) { pr_debug("nf_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive); info->timeout = rrq->timeToLive; } else info->timeout = default_rrq_ttl; return 0; }
static void pptp_exp_gre(struct nf_conntrack_expect *expect_orig, struct nf_conntrack_expect *expect_reply) { const struct nf_conn *ct = expect_orig->master; struct nf_ct_pptp_master *ct_pptp_info; struct nf_nat_pptp *nat_pptp_info; ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info; nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info; #ifdef CONFIG_HTC_NETWORK_MODIFY if (IS_ERR(ct_pptp_info) || (!ct_pptp_info)) printk(KERN_ERR "[NET] ct_pptp_info is NULL in %s!\n", __func__); if (IS_ERR(nat_pptp_info) || (!nat_pptp_info)) printk(KERN_ERR "[NET] nat_pptp_info is NULL in %s!\n", __func__); #endif /* save original PAC call ID in nat_info */ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; /* alter expectation for PNS->PAC direction */ expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id; expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id; expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id; expect_orig->dir = IP_CT_DIR_ORIGINAL; /* alter expectation for PAC->PNS direction */ expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id; expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id; expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id; expect_reply->dir = IP_CT_DIR_REPLY; }
static inline int ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) { struct nlattr *nest_helper; const struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_helper *helper; if (!help) return 0; rcu_read_lock(); helper = rcu_dereference(help->helper); if (!helper) goto out; nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED); if (!nest_helper) goto nla_put_failure; NLA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); if (helper->to_nlattr) helper->to_nlattr(skb, ct); nla_nest_end(skb, nest_helper); out: rcu_read_unlock(); return 0; nla_put_failure: rcu_read_unlock(); return -1; }
static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress *taddr, int count) { struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int ret = 0; int i; __be16 port; union nf_inet_addr addr; struct nf_conntrack_expect *exp; typeof(nat_q931_hook) nat_q931; #ifdef CONFIG_HTC_NETWORK_MODIFY if (IS_ERR(info) || (!info)) printk(KERN_ERR "[NET] info is NULL in %s!\n", __func__); #endif for (i = 0; i < count; i++) { if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) == 0 && port != 0) break; } if (i >= count) return 0; if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), gkrouted_only ? &ct->tuplehash[!dir].tuple.src.u3 : NULL, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_TCP, NULL, &port); exp->helper = nf_conntrack_helper_q931; exp->flags = NF_CT_EXPECT_PERMANENT; nat_q931 = rcu_dereference(nat_q931_hook); if (nat_q931 && ct->status & IPS_NAT_MASK) { ret = nat_q931(skb, ct, ctinfo, data, taddr, i, port, exp); } else { if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_ras: expect Q.931 "); nf_ct_dump_tuple(&exp->tuple); info->sig_port[dir] = port; } else ret = -1; } nf_ct_expect_put(exp); return ret; }
static int nat_h245(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, TransportAddress *taddr, __be16 port, struct nf_conntrack_expect *exp) { struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); u_int16_t nated_port = ntohs(port); /* Set expectations for NAT */ exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; exp->expectfn = nf_nat_follow_master; exp->dir = !dir; /* Check existing expects */ if (info->sig_port[dir] == port) nated_port = ntohs(info->sig_port[!dir]); /* Try to get same port: if not, try to change it. */ for (; nated_port != 0; nated_port++) { int ret; exp->tuple.dst.u.tcp.port = htons(nated_port); ret = nf_ct_expect_related(exp); if (ret == 0) break; else if (ret != -EBUSY) { nated_port = 0; break; } } if (nated_port == 0) { /* No port available */ if (net_ratelimit()) pr_notice("nf_nat_q931: out of TCP ports\n"); return 0; } /* Modify signal */ if (set_h225_addr(skb, data, dataoff, taddr, &ct->tuplehash[!dir].tuple.dst.u3, htons(nated_port)) == 0) { /* Save ports */ info->sig_port[dir] = port; info->sig_port[!dir] = htons(nated_port); } else { nf_ct_unexpect_related(exp); return -1; } pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n", &exp->tuple.src.u3.ip, ntohs(exp->tuple.src.u.tcp.port), &exp->tuple.dst.u3.ip, ntohs(exp->tuple.dst.u.tcp.port)); return 0; }
static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress *taddr, int count) { const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int i; __be16 port; union nf_inet_addr addr; #ifdef CONFIG_HTC_NETWORK_MODIFY if (IS_ERR(info) || (!info)) printk(KERN_ERR "[NET] info is NULL in %s!\n", __func__); #endif for (i = 0; i < count; i++) { if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && port == info->sig_port[dir]) { /* GW->GK */ /* Fix for Gnomemeeting */ if (i > 0 && get_h225_addr(ct, *data, &taddr[0], &addr, &port) && (ntohl(addr.ip) & 0xff000000) == 0x7f000000) i = 0; pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n", &addr.ip, port, &ct->tuplehash[!dir].tuple.dst.u3.ip, info->sig_port[!dir]); return set_h225_addr(skb, data, 0, &taddr[i], &ct->tuplehash[!dir]. tuple.dst.u3, info->sig_port[!dir]); } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && port == info->sig_port[dir]) { /* GK->GW */ pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n", &addr.ip, port, &ct->tuplehash[!dir].tuple.src.u3.ip, info->sig_port[!dir]); return set_h225_addr(skb, data, 0, &taddr[i], &ct->tuplehash[!dir]. tuple.src.u3, info->sig_port[!dir]); } } } return 0; }
static unsigned int ipv4_confirm(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; unsigned int ret; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED_REPLY) goto out; help = nfct_help(ct); if (!help) goto out; /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) goto out; #if defined(CONFIG_RA_HW_NAT) || defined(CONFIG_RA_HW_NAT_MODULE) if (IS_SPACE_AVAILABLED(skb) && IS_MAGIC_TAG_VALID(skb)) { FOE_ALG(skb)=1; } #endif ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo); if (ret != NF_ACCEPT) { nf_log_packet(NFPROTO_IPV4, hooknum, skb, in, out, NULL, "nf_ct_%s: dropping packet", helper->name); return ret; } /* adjust seqs for loopback traffic only in outgoing direction */ if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && !nf_is_loopback_packet(skb)) { typeof(nf_nat_seq_adjust_hook) seq_adjust; seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) { NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); return NF_DROP; } } out: /* We've seen it coming out the other side: confirm it */ return nf_conntrack_confirm(skb); }
static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress *taddr, int count) { struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int i; __be16 port; union nf_inet_addr addr; for (i = 0; i < count; i++) { if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && port == info->sig_port[dir]) { /* GW->GK */ /* Fix for Gnomemeeting */ if (i > 0 && get_h225_addr(ct, *data, &taddr[0], &addr, &port) && (ntohl(addr.ip) & 0xff000000) == 0x7f000000) i = 0; DEBUGP ("nf_nat_ras: set signal address " "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(ip), port, NIPQUAD(ct->tuplehash[!dir].tuple.dst. ip), info->sig_port[!dir]); return set_h225_addr(skb, data, 0, &taddr[i], &ct->tuplehash[!dir]. tuple.dst.u3, info->sig_port[!dir]); } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && port == info->sig_port[dir]) { /* GK->GW */ DEBUGP ("nf_nat_ras: set signal address " "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(ip), port, NIPQUAD(ct->tuplehash[!dir].tuple.src. ip), info->sig_port[!dir]); return set_h225_addr(skb, data, 0, &taddr[i], &ct->tuplehash[!dir]. tuple.src.u3, info->sig_port[!dir]); } } } return 0; }
static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress *taddr, int count) { const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int i; __be16 port; union nf_inet_addr addr; <<<<<<< HEAD
static int process_rcf(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, RegistrationConfirm *rcf) { struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); int ret; struct nf_conntrack_expect *exp; typeof(set_sig_addr_hook) set_sig_addr; pr_debug("nf_ct_ras: RCF\n"); #ifdef CONFIG_HTC_NETWORK_MODIFY if (IS_ERR(info) || (!info)) printk(KERN_ERR "[NET] info is NULL in %s!\n", __func__); #endif set_sig_addr = rcu_dereference(set_sig_addr_hook); if (set_sig_addr && ct->status & IPS_NAT_MASK) { ret = set_sig_addr(skb, ct, ctinfo, data, rcf->callSignalAddress.item, rcf->callSignalAddress.count); if (ret < 0) return -1; } if (rcf->options & eRegistrationConfirm_timeToLive) { pr_debug("nf_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive); info->timeout = rcf->timeToLive; } if (info->timeout > 0) { pr_debug("nf_ct_ras: set RAS connection timeout to " "%u seconds\n", info->timeout); nf_ct_refresh(ct, skb, info->timeout * HZ); spin_lock_bh(&nf_conntrack_lock); exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3, info->sig_port[!dir]); if (exp) { pr_debug("nf_ct_ras: set Q.931 expect " "timeout to %u seconds for", info->timeout); nf_ct_dump_tuple(&exp->tuple); set_expect_timeout(exp, info->timeout); } spin_unlock_bh(&nf_conntrack_lock); } return 0; }
static unsigned int ipv4_confirm(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; unsigned int ret; ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED_REPLY) goto out; help = nfct_help(ct); if (!help) goto out; helper = rcu_dereference(help->helper); if (!helper) goto out; ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo); if (ret != NF_ACCEPT) { nf_log_packet(NFPROTO_IPV4, hooknum, skb, in, out, NULL, "nf_ct_%s: dropping packet", helper->name); return ret; } if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && !nf_is_loopback_packet(skb)) { typeof(nf_nat_seq_adjust_hook) seq_adjust; seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) { NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); return NF_DROP; } } out: return nf_conntrack_confirm(skb); }
static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) { struct xt_ct_target_info *info = par->targinfo; struct nf_conn *ct = info->ct; struct nf_conn_help *help; if (!nf_ct_is_untracked(ct)) { help = nfct_help(ct); if (help) module_put(help->helper->me); nf_ct_l3proto_module_put(par->family); } nf_ct_put(info->ct); }
static unsigned int ipv4_confirm(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; unsigned int ret; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) goto out; help = nfct_help(ct); if (!help) goto out; /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) goto out; ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), ct, ctinfo); //Alpha if (ret != NF_ACCEPT) { nf_log_packet(NFPROTO_IPV4, hooknum, skb, in, out, NULL, "nf_ct_%s: dropping packet", helper->name); return ret; } if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { typeof(nf_nat_seq_adjust_hook) seq_adjust; seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) { NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); return NF_DROP; } } out: /* We've seen it coming out the other side: confirm it */ return nf_conntrack_confirm(skb); }
static unsigned int ipv6_confirm(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; struct nf_conn_help *help; enum ip_conntrack_info ctinfo; unsigned int ret, protoff; unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data; unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(*pskb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) goto out; help = nfct_help(ct); if (!help || !help->helper) goto out; protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, (*pskb)->len - extoff); if (protoff < 0 || protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) { DEBUGP("proto header not found\n"); return NF_ACCEPT; } #if defined(CONFIG_RA_HW_NAT) || defined(CONFIG_RA_HW_NAT_MODULE) if( (skb_headroom(*pskb) >=4) && ((FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_PCI) || (FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_WLAN) || (FOE_MAGIC_TAG(*pskb) == FOE_MAGIC_GE))){ FOE_ALG_RXIF(*pskb)=1; } #endif ret = help->helper->help(pskb, protoff, ct, ctinfo); if (ret != NF_ACCEPT) return ret; out: /* We've seen it coming out the other side: confirm it */ return nf_conntrack_confirm(pskb); }
/* 'skb' should already be pulled to nh_ofs. */ static int ovs_ct_helper(struct sk_buff *skb, u16 proto) { const struct nf_conntrack_helper *helper; const struct nf_conn_help *help; enum ip_conntrack_info ctinfo; unsigned int protoff; struct nf_conn *ct; ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED_REPLY) return NF_ACCEPT; help = nfct_help(ct); if (!help) return NF_ACCEPT; helper = rcu_dereference(help->helper); if (!helper) return NF_ACCEPT; switch (proto) { case NFPROTO_IPV4: protoff = ip_hdrlen(skb); break; case NFPROTO_IPV6: { u8 nexthdr = ipv6_hdr(skb)->nexthdr; __be16 frag_off; int ofs; ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, &frag_off); if (ofs < 0 || (frag_off & htons(~0x7)) != 0) { pr_debug("proto header not found\n"); return NF_ACCEPT; } protoff = ofs; break; } default: WARN_ONCE(1, "helper invoked on non-IP family!"); return NF_DROP; } return helper->help(skb, protoff, ct, ctinfo); }
static int process_arq(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned char **data, AdmissionRequest *arq) { const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; int dir = CTINFO2DIR(ctinfo); __be16 port; union nf_inet_addr addr; typeof(set_h225_addr_hook) set_h225_addr; pr_debug("nf_ct_ras: ARQ\n"); #ifdef CONFIG_HTC_NETWORK_MODIFY if (IS_ERR(info) || (!info)) printk(KERN_ERR "[NET] info is NULL in %s!\n", __func__); #endif set_h225_addr = rcu_dereference(set_h225_addr_hook); if ((arq->options & eAdmissionRequest_destCallSignalAddress) && get_h225_addr(ct, *data, &arq->destCallSignalAddress, &addr, &port) && !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && port == info->sig_port[dir] && set_h225_addr && ct->status & IPS_NAT_MASK) { return set_h225_addr(skb, data, 0, &arq->destCallSignalAddress, &ct->tuplehash[!dir].tuple.dst.u3, info->sig_port[!dir]); } if ((arq->options & eAdmissionRequest_srcCallSignalAddress) && get_h225_addr(ct, *data, &arq->srcCallSignalAddress, &addr, &port) && !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) && set_h225_addr && ct->status & IPS_NAT_MASK) { return set_h225_addr(skb, data, 0, &arq->srcCallSignalAddress, &ct->tuplehash[!dir].tuple.dst.u3, port); } return 0; }
static unsigned int ipv6_confirm(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; struct nf_conn_help *help; struct nf_conntrack_helper *helper; enum ip_conntrack_info ctinfo; unsigned int ret, protoff; unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data; unsigned char pnum = ipv6_hdr(*pskb)->nexthdr; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(*pskb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) goto out; help = nfct_help(ct); if (!help) goto out; /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) goto out; protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, (*pskb)->len - extoff); if (protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) { DEBUGP("proto header not found\n"); return NF_ACCEPT; } ret = helper->help(pskb, protoff, ct, ctinfo); if (ret != NF_ACCEPT) return ret; out: /* We've seen it coming out the other side: confirm it */ return nf_conntrack_confirm(pskb); }
static bool match(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_helper_info *info = par->matchinfo; struct nf_conn *ct; struct nf_conn_help *master_help; enum ip_conntrack_info ctinfo; bool ret = info->invert; ct = nf_ct_get((struct sk_buff *)skb, &ctinfo); if (!ct) { DEBUGP("xt_helper: Eek! invalid conntrack?\n"); return ret; } if (!ct->master) { DEBUGP("xt_helper: conntrack %p has no master\n", ct); return ret; } read_lock_bh(&nf_conntrack_lock); master_help = nfct_help(ct->master); if (!master_help || !master_help->helper) { DEBUGP("xt_helper: master ct %p has no helper\n", exp->expectant); goto out_unlock; } DEBUGP("master's name = %s , info->name = %s\n", ct->master->helper->name, info->name); if (info->name[0] == '\0') ret = !ret; else ret ^= !strncmp(master_help->helper->name, info->name, strlen(master_help->helper->name)); out_unlock: read_unlock_bh(&nf_conntrack_lock); return ret; }