📄 ipv4.c
字号:
/*Copyright (c) 2003,2004 Jeremy Kerr & Rusty RussellThis file is part of nfsim.nfsim is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.nfsim is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with nfsim; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include "ipv4.h"#include "utils.h"#include <core.h>#include <field.h>#if 0#include <linux/netfilter_ipv4.h>#endifint route(struct sk_buff *skb);LIST_HEAD(routes);static struct notifier_block *inetaddr_chain;static int __ip_route_output_key(struct rtable **rp, struct flowi *flp);static int destroy_route(void *r){ struct ipv4_route *route = r; list_del(&route->entry); return 0;}void add_route_for_device(struct in_device *indev){ struct ipv4_route *route; route = talloc(indev, struct ipv4_route); talloc_set_destructor(route, destroy_route); route->netmask = indev->ifa_list->ifa_mask; route->network = indev->ifa_list->ifa_address & indev->ifa_list->ifa_mask; route->interface = indev->dev; route->gateway = indev->ifa_list->ifa_address; list_add_tail(&route->entry, &routes);}struct rtable *rcache;static int destroy_rtable(void *r){ struct rtable *rt = r, **p; /* Remove from cache if it's there (it should be, currently) */ for (p = &rcache; *p; p = &(*p)->u.rt_next) { if (*p == rt) { *p = rt->u.rt_next; break; } } return 0;}#if 0/* need the following: - interfaces - routes */static void init(void){ /* name our hooks */ nf_hooknames[PF_INET][0] = "NF_IP_PRE_ROUTING"; nf_hooknames[PF_INET][1] = "NF_IP_LOCAL_IN"; nf_hooknames[PF_INET][2] = "NF_IP_FORWARD"; nf_hooknames[PF_INET][3] = "NF_IP_LOCAL_OUT"; nf_hooknames[PF_INET][4] = "NF_IP_POST_ROUTING";}init_call(init);#endifint register_inetaddr_notifier(struct notifier_block *nb){ return notifier_chain_register(&inetaddr_chain, nb);}int unregister_inetaddr_notifier(struct notifier_block *nb){ return notifier_chain_unregister(&inetaddr_chain, nb);}int __call_inetaddr_notifier(unsigned long val, struct in_ifaddr *ifa){ struct notifier_block *nb = inetaddr_chain; return notifier_call_chain(&nb, val, ifa);}#if 0static int ip_rcv_finish(struct sk_buff *skb){ if (!skb->dst && ip_route_input(skb, skb->nh.iph->daddr, skb->nh.iph->saddr, skb->nh.iph->tos, skb->dev)) { kfree_skb(skb); return -1; } return dst_input(skb);}#endifint ip_rcv(struct sk_buff *skb){#if 0 skb->dev->stats.rxpackets++; skb->dev->stats.rxbytes += skb->len; /* pull data to the start of the ip header */ skb_pull(skb, skb->nh.raw - skb->data); log_packet(skb, "rcv:%s", skb->dev->name); return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, skb->dev, NULL, ip_rcv_finish);#else return 0;#endif}int ip_rcv_local(struct sk_buff *skb){ struct rtable *rt; struct flowi fl; log_packet(skb, "rcv_local"); /* pull data to the start of the ip header */ skb_pull(skb, skb->nh.raw - skb->data); rt = (struct rtable *)skb->dst; if (rt) goto routed; memset(&fl, 0, sizeof(fl)); fl.fl4_dst = skb->nh.iph->daddr; fl.fl4_src = skb->nh.iph->saddr; fl.fl4_tos = skb->nh.iph->tos;#ifdef CONFIG_IP_ROUTE_FWMARK fl.fl4_fwmark = skb->nfmark;#endif if (__ip_route_output_key(&rt, &fl)) { log_route(skb, "no route"); kfree_skb(skb); return 1; } skb->dst = (struct dst_entry *)rt; dst_hold(skb_dst);routed: skb->dev = skb->dst->dev;#if 0 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dev, dst_output);#else return 0;#endif}static int ip_local_deliver(struct sk_buff *skb){#if 0 return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL, nf_send_local);#else return 0;#endif}int ip_finish_output(struct sk_buff *skb){ struct net_device *dev = skb->dst->dev; skb->dev = dev; skb->protocol = htons(ETH_P_IP); /* if (skb->mac.ethernet) skb->mac.ethernet->h_proto = skb->protocol; */#if 0 return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev, nf_send);#else return 0;#endif }static int ip_output(struct sk_buff *skb){ /* FIXME: fragment? */ return ip_finish_output(skb);}unsigned short ip_compute_csum(unsigned char * buff, int len){ return csum_fold (csum_partial(buff, len, 0));}static int __ip_route_output_key(struct rtable **rp, struct flowi *flp){ struct rtable *rth; struct net_device *dev; struct ipv4_route *route; if (should_i_fail(__func__)) return -ENOMEM; /* check for a cached route */ for (rth = rcache; rth; rth = rth->u.rt_next) { if (rth->fl.fl4_dst == flp->fl4_dst && rth->fl.fl4_src == flp->fl4_src && rth->fl.iif == 0 && rth->fl.oif == flp->oif &&#ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark == flp->fl4_fwmark &&#endif rth->fl.fl4_tos == flp->fl4_tos) { dst_hold(&rth->u.dst) *rp = rth; return 0; } } list_for_each_entry(dev, &interfaces, entry) { struct in_ifaddr *ifaddr; if (!dev->ip_ptr) continue; ifaddr = ((struct in_device *)(dev->ip_ptr))->ifa_list; while (ifaddr) { if (flp->fl4_dst == ifaddr->ifa_local) { rth = talloc_zero(dev->ip_ptr, struct rtable); talloc_set_destructor(rth, destroy_rtable); rth->u.dst.output = ip_output; rth->u.dst.input = ip_local_deliver; rth->u.dst.dev = &loopback_dev;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) rth->u.dst.pmtu = 1500;#endif rth->rt_src = rth->fl.fl4_src = flp->fl4_src; rth->rt_dst = rth->fl.fl4_dst = flp->fl4_dst; rth->rt_gateway = flp->fl4_dst; rth->rt_iif = rth->fl.iif = flp->iif; rth->fl.fl4_tos = flp->fl4_tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark = flp->fl4_fwmark;#endif rth->u.rt_next = rcache; rcache = rth; *rp = rth; return 0; } ifaddr = ifaddr->ifa_next; } } /* otherwise, find the appropriate route & create an rcache entry */ list_for_each_entry(route, &routes, entry) { if ((flp->fl4_dst & route->netmask) == route->network) { rth = talloc_zero(route, struct rtable); talloc_set_destructor(rth, destroy_rtable); rth->u.dst.dev = route->interface; rth->u.dst.output = ip_output; rth->u.dst.input = NULL;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) rth->u.dst.pmtu = 1500;#endif rth->rt_src = rth->fl.fl4_src = flp->fl4_src; if (!rth->rt_src) rth->rt_src = inet_select_addr(route->interface, flp->fl4_dst, RT_SCOPE_UNIVERSE); rth->rt_dst = rth->fl.fl4_dst = flp->fl4_dst; rth->rt_gateway = route->gateway; rth->fl.oif = route->interface->ifindex; rth->fl.oif = flp->oif; rth->fl.fl4_tos = flp->fl4_tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark = flp->fl4_fwmark;#endif /* add to rcache list */ rth->u.rt_next = rcache; rcache = rth; *rp = rth; return 0; } } return 1; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)int ip_route_output_key(struct rtable **rp, struct rt_key *key){ struct flowi fl; fl.fl4_dst = key->dst; fl.fl4_src = key->src; fl.iif = 0; fl.oif = key->oif;#ifdef CONFIG_IP_ROUTE_FWMARK fl.fl4_fwmark = key->fwmark;#endif fl.fl4_tos = key->tos; return __ip_route_output_key(rp, &fl);}#elseint ip_route_output_key(struct rtable **rp, struct flowi *flp){ return __ip_route_output_key(rp, flp);}#endif/* 2.6.10-rc3 added this. */int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, struct sock *sk, int flags){ struct rtable **rp = (void *)dst_p; return __ip_route_output_key(rp, fl);}#if 0static int ip_forward(struct sk_buff *skb){ u32 check; if (!(--skb->nh.iph->ttl)) { log_route(skb, "ip_forward:ttl expired"); icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); kfree_skb(skb); return 1; } nfsim_update_skb(skb, &skb->nh.iph->ttl, sizeof(skb->nh.iph->ttl)); check = skb->nh.iph->check; check += htons(0x0100); skb->nh.iph->check = check + (check>=0xFFFF); /* Tell nfsim it's me changing data here. */ nfsim_update_skb(skb, &skb->nh.iph->check, sizeof(skb->nh.iph->check)); /* FIXME: strict source routing... */#if 0 return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, skb->dst->dev, dst_output);#else return 0;#endif}#endif#if 0int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, u8 tos, struct net_device *dev){ struct rtable *rth; struct ipv4_route *route; int iif = dev->ifindex; for (rth = rcache; rth; rth = rth->u.rt_next) { if (rth->fl.fl4_dst == daddr && rth->fl.fl4_src == saddr && rth->fl.iif == iif && rth->fl.oif == 0 &&#ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark == skb->nfmark &&#endif rth->fl.fl4_tos == tos) { dst_hold(&rth->u.dst); skb->dst = (struct dst_entry*)rth; return 0; } } /* is this a local packet ? */ list_for_each_entry(dev, &interfaces, entry) { struct in_ifaddr *ifaddr; if (!dev->ip_ptr) continue; ifaddr = ((struct in_device *)(dev->ip_ptr))->ifa_list; while (ifaddr) { if (skb->nh.iph->daddr == ifaddr->ifa_local) { log_route(skb, "route:local packet (%s)", dev->name); rth = talloc_zero(dev->ip_ptr, struct rtable); talloc_set_destructor(rth, destroy_rtable); rth->u.dst.output = NULL; rth->u.dst.input = ip_local_deliver; rth->u.dst.dev = &loopback_dev; rth->rt_src = rth->fl.fl4_src = saddr; rth->rt_dst = rth->fl.fl4_dst = daddr; rth->rt_gateway = daddr; rth->rt_iif = rth->fl.iif = dev->ifindex; rth->fl.fl4_tos = tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark = skb->nfmark;#endif skb->dst = &rth->u.dst; return 0; } ifaddr = ifaddr->ifa_next; } } /* otherwise, find the appropriate route & create an rcache entry */ list_for_each_entry(route, &routes, entry) { if ((skb->nh.iph->daddr & route->netmask) == route->network) { rth = talloc_zero(route, struct rtable); talloc_set_destructor(rth, destroy_rtable); rth->u.dst.dev = route->interface; rth->u.dst.output = ip_output; rth->u.dst.input = ip_forward; rth->rt_src = rth->fl.fl4_src = saddr; rth->rt_dst = rth->fl.fl4_dst = daddr; rth->rt_gateway = route->gateway; rth->rt_iif = rth->fl.iif = route->interface->ifindex; rth->fl.oif = 0; rth->fl.fl4_tos = tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->fl.fl4_fwmark = skb->nfmark;#endif /* add to rcache list */ rth->u.rt_next = rcache; rcache = rth; skb->dst = &rth->u.dst; return 0; } } log_route(skb, "ERROR: packet is not local and no matching " "route (dst=%u.%u.%u.%u)", NIPQUAD(daddr)); return 1;}#endifint ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)){ log_packet(skb, "ip_fragment"); (*output)(skb); return 0;}struct fraglist{ struct list_head list; struct sk_buff *frags[20];};static struct list_head fraglist[IP_DEFRAG_VS_FWD];static void init_fraglist(void){ unsigned int i; for (i = 0; i < ARRAY_SIZE(fraglist); i++) INIT_LIST_HEAD(&fraglist[i]);}init_call(init_fraglist);#if 0static struct sk_buff *gather_frag(struct fraglist *f, struct sk_buff *skb){ unsigned int i, len, off, max = 0; bool ended = false; char filled[70000] = { 0 }; char data[70000]; for (i = 0; i < ARRAY_SIZE(f->frags); i++) { if (!f->frags[i]) { if (!skb) break; f->frags[i] = skb; talloc_steal(f, skb); skb = NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -