static unsigned int nf_route_table_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { unsigned int ret; struct nft_pktinfo pkt; struct in6_addr saddr, daddr; u_int8_t hop_limit; u32 mark, flowlabel; /* malformed packet, drop it */ if (nft_set_pktinfo_ipv6(&pkt, skb, state) < 0) return NF_DROP; /* save source/dest address, mark, hoplimit, flowlabel, priority */ memcpy(&saddr, &ipv6_hdr(skb)->saddr, sizeof(saddr)); memcpy(&daddr, &ipv6_hdr(skb)->daddr, sizeof(daddr)); mark = skb->mark; hop_limit = ipv6_hdr(skb)->hop_limit; /* flowlabel and prio (includes version, which shouldn't change either */ flowlabel = *((u32 *)ipv6_hdr(skb)); ret = nft_do_chain(&pkt, priv); if (ret != NF_DROP && ret != NF_QUEUE && (memcmp(&ipv6_hdr(skb)->saddr, &saddr, sizeof(saddr)) || memcmp(&ipv6_hdr(skb)->daddr, &daddr, sizeof(daddr)) || skb->mark != mark || ipv6_hdr(skb)->hop_limit != hop_limit || flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) return ip6_route_me_harder(state->net, skb) == 0 ? ret : NF_DROP; return ret; }
static unsigned int nf_nat_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); struct nf_conn_nat *nat; enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum); unsigned int ret; if (ct == NULL || nf_ct_is_untracked(ct)) return NF_ACCEPT; NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET))); nat = nfct_nat(ct); if (nat == NULL) { /* Conntrack module was loaded late, can't add extension. */ if (nf_ct_is_confirmed(ct)) return NF_ACCEPT; nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); if (nat == NULL) return NF_ACCEPT; } switch (ctinfo) { case IP_CT_RELATED: case IP_CT_RELATED + IP_CT_IS_REPLY: if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, ops->hooknum)) return NF_DROP; else return NF_ACCEPT; } /* Fall through */ case IP_CT_NEW: if (nf_nat_initialized(ct, maniptype)) break; ret = nft_do_chain(ops, skb, in, out, okfn); if (ret != NF_ACCEPT) return ret; if (!nf_nat_initialized(ct, maniptype)) { ret = nf_nat_alloc_null_binding(ct, ops->hooknum); if (ret != NF_ACCEPT) return ret; } default: break; } return nf_nat_packet(ct, ctinfo, ops->hooknum, skb); }
static unsigned int nft_do_chain_arp(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { struct nft_pktinfo pkt; nft_set_pktinfo(&pkt, skb, state); return nft_do_chain(&pkt, priv); }
static unsigned int nft_nat_do_chain(void *priv, struct sk_buff *skb, const struct nf_hook_state *state, struct nf_conn *ct) { struct nft_pktinfo pkt; nft_set_pktinfo_ipv4(&pkt, skb, state); return nft_do_chain(&pkt, priv); }
static unsigned int nft_nat_do_chain(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state, struct nf_conn *ct) { struct nft_pktinfo pkt; nft_set_pktinfo_ipv6(&pkt, ops, skb, state); return nft_do_chain(&pkt, ops); }
static unsigned int nft_do_chain_ipv6(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { struct nft_pktinfo pkt; /* malformed packet, drop it */ if (nft_set_pktinfo_ipv6(&pkt, skb, state) < 0) return NF_DROP; return nft_do_chain(&pkt, priv); }
static unsigned int nft_do_chain_bridge(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct nft_pktinfo pkt; nft_set_pktinfo(&pkt, ops, skb, in, out); return nft_do_chain(&pkt, ops); }
static unsigned int nft_ipv4_output(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { if (unlikely(skb->len < sizeof(struct iphdr) || ip_hdr(skb)->ihl < sizeof(struct iphdr) / 4)) { if (net_ratelimit()) pr_info("nf_tables_ipv4: ignoring short SOCK_RAW " "packet\n"); return NF_ACCEPT; } return nft_do_chain(ops, skb, in, out, okfn); }
static unsigned int nft_do_chain_netdev(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct nf_hook_state *state) { struct nft_pktinfo pkt; switch (eth_hdr(skb)->h_proto) { case htons(ETH_P_IP): nft_netdev_set_pktinfo_ipv4(&pkt, ops, skb, state); break; case htons(ETH_P_IPV6): nft_netdev_set_pktinfo_ipv6(&pkt, ops, skb, state); break; default: nft_set_pktinfo(&pkt, ops, skb, state); break; } return nft_do_chain(&pkt, ops); }
static unsigned int nft_nat_do_chain(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { struct nft_pktinfo pkt; nft_set_pktinfo(&pkt, skb, state); switch (state->pf) { #ifdef CONFIG_NF_TABLES_IPV4 case NFPROTO_IPV4: nft_set_pktinfo_ipv4(&pkt, skb); break; #endif #ifdef CONFIG_NF_TABLES_IPV6 case NFPROTO_IPV6: nft_set_pktinfo_ipv6(&pkt, skb); break; #endif default: break; } return nft_do_chain(&pkt, priv); }