📄 arp.c
字号:
/* arp.c * linqianghe@163.com * 2006-09-26 */#include "neighbour.h"#include "dev.h"#include "dev_dummy.h"#include "af_inet.h"#include "arp.h"#include "log.h"#include "route.h"#include "fib_frontend.h"#include "devinet.h"#include <linux/inetdevice.h>#include <linux/if_arp.h>#include <linux/rtnetlink.h>#include <linux/jhash.h>#include <linux/netfilter_arp.h>#include <linux/in.h>extern struct neigh_table myarp_tbl;struct sk_buff *myarp_create(int type, int ptype, u32 dest_ip, struct net_device *dev, u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *target_hw){ struct sk_buff *skb; struct arphdr *arp; unsigned char *arp_ptr; skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) + LL_RESERVED_SPACE(dev), GFP_ATOMIC); if( skb == NULL ) return NULL; skb_reserve( skb, LL_RESERVED_SPACE(dev) ); skb->nh.raw = skb->data; arp = (struct arphdr *) skb_put( skb,sizeof(struct arphdr) + 2*(dev->addr_len+4) ); skb->dev = dev; skb->protocol = htons(ETH_P_ARP); if( src_hw == NULL ) src_hw = dev->dev_addr; if( dest_hw == NULL ) dest_hw = dev->broadcast; if( dev->hard_header && dev->hard_header(skb,dev,ptype,dest_hw,src_hw,skb->len) < 0 ) goto out; switch( dev->type ){ default: arp->ar_hrd = htons(dev->type); arp->ar_pro = htons(ETH_P_IP); break; } arp->ar_hln = dev->addr_len; arp->ar_pln = 4; arp->ar_op = htons(type); arp_ptr=(unsigned char *)(arp+1); memcpy(arp_ptr, src_hw, dev->addr_len); arp_ptr+=dev->addr_len; memcpy(arp_ptr, &src_ip,4); arp_ptr+=4; if (target_hw != NULL) memcpy(arp_ptr, target_hw, dev->addr_len); else memset(arp_ptr, 0, dev->addr_len); arp_ptr += dev->addr_len; memcpy(arp_ptr, &dest_ip, 4); return skb;out: kfree_skb(skb); return NULL;}void myarp_xmit(struct sk_buff *skb){ NF_HOOK( NF_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit );}void myarp_send( int type, int ptype, u32 dest_ip, struct net_device *dev, u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, unsigned char *target_hw ){ struct sk_buff *skb; if( dev->flags & IFF_NOARP ) return; skb = myarp_create(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, target_hw); if (skb == NULL) return; myarp_xmit(skb);}static void myarp_solicit(struct neighbour *neigh, struct sk_buff *skb){ u32 saddr = 0; u8 *dst_ha = NULL; struct net_device *dev = neigh->dev; u32 target = *(u32*)neigh->primary_key; int probes = atomic_read(&neigh->probes); struct in_device *in_dev = in_dev_get(dev); if (!in_dev) return;/* switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { default: case 0: if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) saddr = skb->nh.iph->saddr; break; case 1: if (!skb) break; saddr = skb->nh.iph->saddr; if (inet_addr_type(saddr) == RTN_LOCAL) { if (inet_addr_onlink(in_dev, target, saddr)) break; } saddr = 0; break; case 2: break; }*/ saddr = 0x023010AC; if (in_dev) in_dev_put(in_dev); if( !saddr ) saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); if( (probes -= neigh->parms->ucast_probes) < 0 ){ if( !(neigh->nud_state & NUD_VALID) ) PR_DEBUG( "trying to ucast probe in NUD_INVALID\n" ); dst_ha = neigh->ha; read_lock_bh(&neigh->lock); } else if ((probes -= neigh->parms->app_probes) < 0) { return; } myarp_send( ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, dst_ha, dev->dev_addr, NULL ); if( dst_ha ) read_unlock_bh(&neigh->lock); dev_put(dev);}static void myarp_error_report(struct neighbour *neigh, struct sk_buff *skb){ PR_DEBUG( "myarp_error_report!\n" ); dst_link_failure( skb ); kfree_skb(skb);}static struct neigh_ops myarp_dummy_ops = { .family = MY_AF_INET, .solicit = myarp_solicit, .error_report = myarp_error_report, .output = myneigh_resolve_output, .connected_output = dev_queue_xmit_dummy, .hh_output = dev_queue_xmit_dummy, .queue_xmit = dev_queue_xmit_dummy,};static struct neigh_ops myarp_generic_ops = { .family = MY_AF_INET, .solicit = myarp_solicit, .error_report = myarp_error_report, .output = myneigh_resolve_output, .connected_output = myneigh_connected_output, .hh_output = mydev_queue_xmit, .queue_xmit = mydev_queue_xmit,};static struct neigh_ops myarp_hh_ops = { .family = MY_AF_INET, .solicit = myarp_solicit, .error_report = myarp_error_report, .output = myneigh_resolve_output, .connected_output = myneigh_resolve_output, .hh_output = mydev_queue_xmit, .queue_xmit = mydev_queue_xmit,};static struct neigh_ops myarp_direct_ops = { .family = MY_AF_INET, .output = mydev_queue_xmit, .connected_output = mydev_queue_xmit, .hh_output = mydev_queue_xmit, .queue_xmit = mydev_queue_xmit,};struct neigh_ops myarp_broken_ops = { .family = MY_AF_INET, .solicit = myarp_solicit, .error_report = myarp_error_report, .output = myneigh_compat_output, .connected_output = myneigh_compat_output, .hh_output = mydev_queue_xmit, .queue_xmit = mydev_queue_xmit,};static u32 myarp_hash(const void *pkey, const struct net_device *dev){ return jhash_2words( *(u32 *)pkey, dev->ifindex, myarp_tbl.hash_rnd);}static int myarp_constructor( struct neighbour *neigh ){ u32 addr = *(u32*)neigh->primary_key; struct net_device *dev = neigh->dev; struct in_device *in_dev; struct neigh_parms *parms; neigh->type = myinet_addr_type(addr); rcu_read_lock(); in_dev = __in_dev_get_rcu( dev ); if( in_dev == NULL ){ rcu_read_unlock(); return -EINVAL; } parms = in_dev->arp_parms; __neigh_parms_put( neigh->parms ); neigh->parms = neigh_parms_clone( parms ); rcu_read_unlock(); if( dev->hard_header == NULL ){ neigh->nud_state = NUD_NOARP; neigh->ops = &myarp_direct_ops; neigh->output = neigh->ops->queue_xmit; }else{ switch( dev->type ){ default: break; case ARPHRD_ROSE: #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) case ARPHRD_AX25:#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) case ARPHRD_NETROM:#endif neigh->ops = &myarp_broken_ops; neigh->output = neigh->ops->output; return 0;#endif ;} if( neigh->type == RTN_MULTICAST ){ neigh->nud_state = NUD_NOARP; //arp_mc_map(addr, neigh->ha, dev, 1); }else if( dev->flags & (IFF_NOARP|IFF_LOOPBACK) ){ neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->dev_addr, dev->addr_len); }else if( neigh->type == RTN_BROADCAST || dev->flags & IFF_POINTOPOINT ){ neigh->nud_state = NUD_NOARP; memcpy(neigh->ha, dev->broadcast, dev->addr_len); } PR_DEBUG( "the hh->hh_data's len: %d, %d\n", sizeof(neigh->hh->hh_data), LL_MAX_HEADER ); if( dev->hard_header_cache ) neigh->ops = &myarp_hh_ops; else neigh->ops = &myarp_generic_ops; if( neigh->nud_state & NUD_VALID ) neigh->output = neigh->ops->connected_output; else neigh->output = neigh->ops->output; } return 0;}static int myarp_process(struct sk_buff *skb){ struct net_device *dev = skb->dev; struct in_device *in_dev = in_dev_get(dev); struct arphdr *arp; unsigned char *arp_ptr; struct rtable *rt; unsigned char *sha, *tha; u32 sip, tip; u16 dev_type = dev->type; int addr_type; struct neighbour *n; if (in_dev == NULL) goto out; arp = skb->nh.arph; switch( dev_type ){ default: if( arp->ar_pro != htons(ETH_P_IP) || htons(dev_type) != arp->ar_hrd ) goto out; break; } if( arp->ar_op != htons(ARPOP_REPLY) && arp->ar_op != htons(ARPOP_REQUEST) ) goto out; arp_ptr= (unsigned char *)(arp+1); sha = arp_ptr; arp_ptr += dev->addr_len; memcpy(&sip, arp_ptr, 4); arp_ptr += 4; tha = arp_ptr; arp_ptr += dev->addr_len; memcpy(&tip, arp_ptr, 4); if( LOOPBACK(tip) || MULTICAST(tip) ) goto out; if( sip == 0 ){ if( arp->ar_op == htons(ARPOP_REQUEST) && inet_addr_type(tip) == RTN_LOCAL /* &&!arp_ignore(in_dev,dev,sip,tip)*/ ) myarp_send( ARPOP_REPLY, ETH_P_ARP, tip, dev, tip, sha, dev->dev_addr, dev->dev_addr); goto out; } if( arp->ar_op == htons(ARPOP_REQUEST) /*&& ip_route_input(skb, tip, sip, 0, dev) == 0*/){ //rt = (struct rtable*)skb->dst; //addr_type = rt->rt_type; addr_type = RTN_LOCAL; if( addr_type == RTN_LOCAL ){ n = myneigh_event_ns( &myarp_tbl, sha, &sip, dev ); if( n ){ int dont_send = 0; //if( !dont_send ) // dont_send |= arp_ignore( in_dev,dev,sip,tip ); //if( !dont_send && IN_DEV_ARPFILTER(in_dev) ) // dont_send |= arp_filter( sip, tip, dev ); PR_DEBUG( "arp replay!!\n" ); if( !dont_send ) myarp_send( ARPOP_REPLY, ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha ); myneigh_release(n); } goto out; }/*else if( IN_DEV_FORWARD(in_dev) ){ if( (rt->rt_flags & RTCF_DNAT) || (addr_type == RTN_UNICAST && rt->u.dst.dev != dev && (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&myarp_tbl, &tip, dev, 0))) ){ n = neigh_event_ns( &myarp_tbl, sha, &sip, dev ); if( n ) neigh_release(n); if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || skb->pkt_type == PACKET_HOST || in_dev->arp_parms->proxy_delay == 0) { myarp_send( ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha ); }else{ pneigh_enqueue( &myarp_tbl, in_dev->arp_parms, skb ); in_dev_put( in_dev ); return 0; } goto out; } }*/ } PR_DEBUG( "do the __myneigh_lookup now!\n"); n = __myneigh_lookup( &myarp_tbl, &sip, dev, 0 ); if( n ){ int state = NUD_REACHABLE; int override; override = time_after(jiffies, n->updated + n->parms->locktime); if( arp->ar_op != htons(ARPOP_REPLY) || skb->pkt_type != PACKET_HOST ) state = NUD_STALE; PR_DEBUG( "neigh_update here!!!\n"); myneigh_update( n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0 ); myneigh_release(n); }else PR_DEBUG( "can't find the neighbour!\n");out: if( in_dev ) in_dev_put(in_dev); kfree_skb(skb); return 0;}static void myparp_redo(struct sk_buff *skb){ myarp_process(skb);}struct neigh_table tmp_tbl = { .family = MY_AF_INET, .entry_size = sizeof(struct neighbour) + 4, .key_len = 4, .hash = myarp_hash, .constructor = myarp_constructor, .proxy_redo = myparp_redo, .id = "myarp_cache", .parms = { .tbl = &myarp_tbl, .base_reachable_time = 30 * HZ, .retrans_time = 1 * HZ, .gc_staletime = 60 * HZ, .reachable_time = 30 * HZ, .delay_probe_time = 5 * HZ, .queue_len = 3, .ucast_probes = 3, .mcast_probes = 3, .anycast_delay = 1 * HZ, .proxy_delay = (8 * HZ) / 10, .proxy_qlen = 64, .locktime = 1 * HZ, }, .gc_interval = 30 * HZ, .gc_thresh1 = 128, .gc_thresh2 = 512, .gc_thresh3 = 1024,};int myarp_bind_neighbour(struct dst_entry *dst){ struct net_device *dev = dst->dev;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -