📄 arp.c
字号:
struct neighbour *n = dst->neighbour; PR_DEBUG( "bind a neighbour to a dst on device: %s!\n", dev->name ); if( dev == NULL ) return -EINVAL; if( n == NULL ){ u32 nexthop = ((struct rtable*)dst)->rt_gateway; if( dev->flags & ( IFF_LOOPBACK | IFF_POINTOPOINT ) ) nexthop = 0; n = __myneigh_lookup_errno( &myarp_tbl, &nexthop, dev ); if( IS_ERR(n) ) return PTR_ERR(n); PR_DEEP_DEBUG( "bind a neighbour %p successed!\n", n ); dst->neighbour = n; } return 0;}static int myarp_req_delete(struct arpreq *r, struct net_device * dev){ int err; u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; if( r->arp_flags & ATF_PUBL ){ u32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; if( mask == 0xFFFFFFFF ) return mypneigh_delete( &myarp_tbl, &ip, dev ); if( mask == 0 ){ if( dev == NULL ){ //myipv4_devconf.proxy_arp = 0; return 0; } if( __in_dev_get_rtnl(dev) ){ __in_dev_get_rtnl(dev)->cnf.proxy_arp = 0; return 0; } return -ENXIO; } return -EINVAL; }/* if (dev == NULL) { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; if ((err = ip_route_output_key(&rt, &fl)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; }*/ err = -ENXIO; neigh = myneigh_lookup( &myarp_tbl, &ip, dev ); if( neigh ){ if( neigh->nud_state & ~NUD_NOARP ) err = myneigh_update( neigh, NULL, NUD_FAILED, NEIGH_UPDATE_F_OVERRIDE|NEIGH_UPDATE_F_ADMIN ); myneigh_release(neigh); } return err;}static int myarp_req_set(struct arpreq *r, struct net_device * dev){ u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err; if( r->arp_flags & ATF_PUBL ){ u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr; if( mask && mask != 0xFFFFFFFF ) return -EINVAL; if( !dev && (r->arp_flags & ATF_COM) ){ dev = dev_getbyhwaddr( r->arp_ha.sa_family, r->arp_ha.sa_data ); if (!dev) return -ENODEV; } if( mask ){ if( mypneigh_lookup(&myarp_tbl, &ip, dev, 1) == NULL ) return -ENOBUFS; return 0; } if (dev == NULL) { //ipv4_devconf.proxy_arp = 1; return 0; } if (__in_dev_get_rtnl(dev)) { __in_dev_get_rtnl(dev)->cnf.proxy_arp = 1; return 0; } return -ENXIO; } if( r->arp_flags & ATF_PERM ) r->arp_flags |= ATF_COM;/* if( dev == NULL ){ struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = RTO_ONLINK } } }; struct rtable * rt; if ((err = ip_route_output_key(&rt, &fl)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; }*/ switch( dev->type ){ default: if( r->arp_ha.sa_family != dev->type ) return -EINVAL; break; } neigh = __myneigh_lookup_errno( &myarp_tbl, &ip, dev ); err = PTR_ERR(neigh); if (!IS_ERR(neigh)) { unsigned state = NUD_STALE; if (r->arp_flags & ATF_PERM) state = NUD_PERMANENT; err = myneigh_update(neigh, (r->arp_flags & ATF_COM) ? r->arp_ha.sa_data : NULL, state, NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN); myneigh_release(neigh); } return err;}static unsigned myarp_state_to_flags(struct neighbour *neigh){ unsigned flags = 0; if( neigh->nud_state & NUD_PERMANENT ) flags = ATF_PERM | ATF_COM; else if( neigh->nud_state & NUD_VALID ) flags = ATF_COM; return flags;}static int myarp_req_get(struct arpreq *r, struct net_device *dev){ u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err = -ENXIO; neigh = myneigh_lookup( &myarp_tbl, &ip, dev ); if( neigh ){ read_lock_bh( &neigh->lock ); memcpy( r->arp_ha.sa_data, neigh->ha, dev->addr_len ); r->arp_flags = myarp_state_to_flags( neigh ); read_unlock_bh( &neigh->lock ); r->arp_ha.sa_family = dev->type; strlcpy( r->arp_dev, dev->name, sizeof(r->arp_dev) ); myneigh_release(neigh); err = 0; } return err;}int myarp_ioctl(unsigned int cmd, void __user *arg){ int err; struct arpreq r; struct net_device *dev = NULL; switch (cmd) { case SIOCDARP: case SIOCSARP: if( !capable(CAP_NET_ADMIN) ) return -EPERM; case SIOCGARP: err = copy_from_user( &r, arg, sizeof(struct arpreq) ); if (err) return -EFAULT; break; default: return -EINVAL; } if( r.arp_pa.sa_family != MY_AF_INET ) return -EPFNOSUPPORT; if( !(r.arp_flags & ATF_PUBL) && (r.arp_flags & (ATF_NETMASK|ATF_DONTPUB)) ) return -EINVAL; if( !(r.arp_flags & ATF_NETMASK) ) ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = htonl(0xFFFFFFFFUL); rtnl_lock(); if( r.arp_dev[0] ){ err = -ENODEV; if( (dev = __dev_get_by_name(r.arp_dev)) == NULL ) goto out; if( !r.arp_ha.sa_family ) r.arp_ha.sa_family = dev->type; err = -EINVAL; if( (r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type ) goto out; }else if( cmd == SIOCGARP ){ err = -ENODEV; goto out; }else{ err = -ENODEV; //tmp code FIXME!! goto out; } switch(cmd) { case SIOCDARP: err = myarp_req_delete( &r, dev ); break; case SIOCSARP: err = myarp_req_set( &r, dev ); break; case SIOCGARP: err = myarp_req_get( &r, dev ); if( !err && copy_to_user(arg, &r, sizeof(r)) ) err = -EFAULT; break; }out: rtnl_unlock(); return err;}static int myarp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr){ //struct net_device *dev = ptr; switch( event ){/* case NETDEV_CHANGEADDR: neigh_changeaddr(&arp_tbl, dev); rt_cache_flush(0); break;*/ default: break; } return NOTIFY_DONE;}static struct notifier_block myarp_netdev_notifier = { .notifier_call = myarp_netdev_event,};int myarp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev){ struct arphdr *arp; if( !pskb_may_pull(skb, (sizeof(struct arphdr) + (2 * dev->addr_len) + (2 * sizeof(u32)))) ) goto freeskb; arp = skb->nh.arph; if (arp->ar_hln != dev->addr_len || dev->flags & IFF_NOARP || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || arp->ar_pln != 4) goto freeskb; if( (skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ) goto out_of_mem; memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); PR_DEBUG( "arp packet received!\n"); return NF_HOOK(NF_ARP, NF_ARP_IN, skb, dev, NULL, myarp_process);freeskb: kfree_skb(skb);out_of_mem: return 0;}#ifdef CONFIG_PROC_FS#define HBUFFERLEN 30static void myarp_format_neigh_entry(struct seq_file *seq, struct neighbour *n){ char hbuffer[HBUFFERLEN]; const char hexbuf[] = "0123456789ABCDEF"; int k, j; char tbuf[16]; struct net_device *dev = n->dev; int hatype = dev->type; read_lock(&n->lock); /* Convert hardware address to XX:XX:XX:XX ... form. */ for (k = 0, j = 0; k < HBUFFERLEN - 3 && j < dev->addr_len; j++) { hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15]; hbuffer[k++] = hexbuf[n->ha[j] & 15]; hbuffer[k++] = ':'; } hbuffer[--k] = 0; sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, myarp_state_to_flags(n), hbuffer, dev->name); read_unlock(&n->lock);}static void myarp_format_pneigh_entry(struct seq_file *seq, struct pneigh_entry *n){ struct net_device *dev = n->dev; int hatype = dev ? dev->type : 0; char tbuf[16]; sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", dev ? dev->name : "*");}static int myarp_seq_show( struct seq_file *seq, void *v ){ if (v == SEQ_START_TOKEN) { seq_puts(seq, "IP address HW type Flags " "HW address Mask Device\n"); } else { struct neigh_seq_state *state = seq->private; if (state->flags & NEIGH_SEQ_IS_PNEIGH) myarp_format_pneigh_entry(seq, v); else myarp_format_neigh_entry(seq, v); } return 0;}static void *myarp_seq_start(struct seq_file *seq, loff_t *pos){ return myneigh_seq_start( seq, pos, &myarp_tbl, NEIGH_SEQ_SKIP_NOARP );}static struct seq_operations myarp_seq_ops = { .start = myarp_seq_start, .next = myneigh_seq_next, .stop = myneigh_seq_stop, .show = myarp_seq_show,};static int myarp_seq_open(struct inode *inode, struct file *file){ struct seq_file *seq; int rc = -ENOMEM; struct neigh_seq_state *s = kmalloc( sizeof(*s), GFP_KERNEL ); if( !s ) goto out; memset(s, 0, sizeof(*s)); rc = seq_open(file, &myarp_seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s;out: return rc;out_kfree: kfree(s); goto out;}static struct file_operations myarp_seq_fops = { .owner = THIS_MODULE, .open = myarp_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};static int __init myarp_proc_init(void){ if( !proc_net_fops_create("myarp", S_IRUGO, &myarp_seq_fops) ) return -ENOMEM; return 0;}#else /* CONFIG_PROC_FS */static int __init myarp_proc_init(void){ return 0;}#endif /* CONFIG_PROC_FS */void myarp_ifdown(struct net_device *dev){ myneigh_ifdown( &myarp_tbl, dev );}static struct packet_type myarp_packet_type = { .type = __constant_htons(ETH_P_ARP), .func = myarp_rcv,};void __init myarp_init(void){ memcpy( &myarp_tbl, &tmp_tbl, sizeof(myarp_tbl) ); myneigh_table_init( &myarp_tbl ); mydev_add_pack( &myarp_packet_type ); myarp_proc_init();#ifdef CONFIG_SYSCTL //neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, // NET_IPV4_NEIGH, "ipv4", NULL, NULL);#endif register_netdevice_notifier( &myarp_netdev_notifier );}void __exit myarp_exit(void){ unregister_netdevice_notifier( &myarp_netdev_notifier ); mydev_remove_pack( &myarp_packet_type ); myneigh_table_destroy( &myarp_tbl );}EXPORT_SYMBOL_GPL( myarp_bind_neighbour );EXPORT_SYMBOL_GPL( myarp_ioctl );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -