📄 arp.c
字号:
if (arp->ar_hrd != __constant_htons(ARPHRD_ETHER) && arp->ar_hrd != __constant_htons(ARPHRD_IEEE802)) goto out; if (arp->ar_pro != __constant_htons(ETH_P_IP)) goto out; break;#endif#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) case ARPHRD_AX25: if (arp->ar_pro != __constant_htons(AX25_P_IP)) goto out; if (arp->ar_hrd != __constant_htons(ARPHRD_AX25)) goto out; break;#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE) case ARPHRD_NETROM: if (arp->ar_pro != __constant_htons(AX25_P_IP)) goto out; if (arp->ar_hrd != __constant_htons(ARPHRD_NETROM)) goto out; break;#endif#endif } /* Undertsand only these message types */ if (arp->ar_op != __constant_htons(ARPOP_REPLY) && arp->ar_op != __constant_htons(ARPOP_REQUEST)) goto out;/* * Extract fields */ 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);/* * Check for bad requests for 127.x.x.x and requests for multicast * addresses. If this is one such, delete it. */ if (LOOPBACK(tip) || MULTICAST(tip)) goto out;/* * Process entry. The idea here is we want to send a reply if it is a * request for us or if it is a request for someone else that we hold * a proxy for. We want to add an entry to our cache if it is a reply * to us or if it is a request for our address. * (The assumption for this last is that if someone is requesting our * address, they are probably intending to talk to us, so it saves time * if we cache their address. Their address is also probably not in * our cache, since ours is not in their cache.) * * Putting this another way, we only care about replies if they are to * us, in which case we add them to the cache. For requests, we care * about those for us and those for our proxies. We reply to both, * and in the case of requests for us we add the requester to the arp * cache. */ /* Special case: IPv4 duplicate address detection packet (RFC2131) */ if (sip == 0) { struct device *dev2; struct in_device *in_dev2; if (arp->ar_op == __constant_htons(ARPOP_REQUEST) && (dev2 = ip_dev_find(tip)) != NULL && (dev2 == dev || ((in_dev2 = dev2->ip_ptr) != NULL && !IN_DEV_HIDDEN(in_dev2)))) arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr); goto out; } if (arp->ar_op == __constant_htons(ARPOP_REQUEST) && ip_route_input(skb, tip, sip, 0, dev) == 0) { rt = (struct rtable*)skb->dst; addr_type = rt->rt_type; if (addr_type == RTN_LOCAL) { n = neigh_event_ns(&arp_tbl, sha, &sip, dev); if (n) { if (ipv4_devconf.hidden && skb->pkt_type != PACKET_HOST) { struct device *dev2; struct in_device *in_dev2; if ((dev2 = ip_dev_find(tip)) != NULL && dev2 != dev && (in_dev2 = dev2->ip_ptr) != NULL && IN_DEV_HIDDEN(in_dev2)) { neigh_release(n); goto out; } } arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); neigh_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 && (IN_DEV_PROXY_ARP(in_dev) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) { n = neigh_event_ns(&arp_tbl, sha, &sip, dev); neigh_release(n); if (skb->stamp.tv_sec == 0 || skb->pkt_type == PACKET_HOST || in_dev->arp_parms->proxy_delay == 0) { arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); } else { pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb); return 0; } goto out; } } } /* Update our ARP tables */ n = __neigh_lookup(&arp_tbl, &sip, dev, 0);#ifdef CONFIG_IP_ACCEPT_UNSOLICITED_ARP /* Unsolicited ARP is not accepted by default. It is possible, that this option should be enabled for some devices (strip is candidate) */ if (n == NULL && arp->ar_op == __constant_htons(ARPOP_REPLY) && inet_addr_type(sip) == RTN_UNICAST) n = __neigh_lookup(&arp_tbl, &sip, dev, -1);#endif if (n) { int state = NUD_REACHABLE; int override = 0; /* If several different ARP replies follows back-to-back, use the FIRST one. It is possible, if several proxy agents are active. Taking the first reply prevents arp trashing and chooses the fastest router. */ if (jiffies - n->updated >= n->parms->locktime) override = 1; /* Broadcast replies and request packets do not assert neighbour reachability. */ if (arp->ar_op != __constant_htons(ARPOP_REPLY) || skb->pkt_type != PACKET_HOST) state = NUD_STALE; neigh_update(n, sha, state, override, 1); neigh_release(n); }out: kfree_skb(skb); return 0;}/* * User level interface (ioctl, /proc) *//* * Set (create) an ARP cache entry. */int arp_req_set(struct arpreq *r, struct 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 (pneigh_lookup(&arp_tbl, &ip, dev, 1) == NULL) return -ENOBUFS; return 0; } if (dev == NULL) { ipv4_devconf.proxy_arp = 1; return 0; } if (dev->ip_ptr) { ((struct in_device*)dev->ip_ptr)->cnf.proxy_arp = 1; return 0; } return -ENXIO; } if (r->arp_flags & ATF_PERM) r->arp_flags |= ATF_COM; if (dev == NULL) { struct rtable * rt; if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } if (r->arp_ha.sa_family != dev->type) return -EINVAL; err = -ENOBUFS; start_bh_atomic(); neigh = __neigh_lookup(&arp_tbl, &ip, dev, 1); if (neigh) { unsigned state = NUD_STALE; if (r->arp_flags & ATF_PERM) state = NUD_PERMANENT; err = neigh_update(neigh, (r->arp_flags&ATF_COM) ? r->arp_ha.sa_data : NULL, state, 1, 0); neigh_release(neigh); } end_bh_atomic(); return err;}static unsigned arp_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;}/* * Get an ARP cache entry. */static int arp_req_get(struct arpreq *r, struct device *dev){ u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; struct neighbour *neigh; int err = -ENXIO; start_bh_atomic(); neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0); if (neigh) { memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); r->arp_ha.sa_family = dev->type; strncpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); r->arp_flags = arp_state_to_flags(neigh); neigh_release(neigh); err = 0; } end_bh_atomic(); return err;}int arp_req_delete(struct arpreq *r, struct 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 pneigh_delete(&arp_tbl, &ip, dev); if (mask == 0) { if (dev == NULL) { ipv4_devconf.proxy_arp = 0; return 0; } if (dev->ip_ptr) { ((struct in_device*)dev->ip_ptr)->cnf.proxy_arp = 0; return 0; } return -ENXIO; } return -EINVAL; } if (dev == NULL) { struct rtable * rt; if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); if (!dev) return -EINVAL; } err = -ENXIO; start_bh_atomic(); neigh = __neigh_lookup(&arp_tbl, &ip, dev, 0); if (neigh) { if (neigh->nud_state&~NUD_NOARP) err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0); neigh_release(neigh); } end_bh_atomic(); return err;}#ifdef _HURD_#define arp_ioctl 0#else/* * Handle an ARP layer I/O control request. */int arp_ioctl(unsigned int cmd, void *arg){ int err; struct arpreq r; struct 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 != 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=__constant_htonl(0xFFFFFFFFUL); rtnl_lock(); if (r.arp_dev[0]) { err = -ENODEV; if ((dev = dev_get(r.arp_dev)) == NULL) goto out; /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ 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; } switch(cmd) { case SIOCDARP: err = arp_req_delete(&r, dev); break; case SIOCSARP: err = arp_req_set(&r, dev); break; case SIOCGARP: err = arp_req_get(&r, dev); if (!err && copy_to_user(arg, &r, sizeof(r))) err = -EFAULT; break; }out: rtnl_unlock(); return err;}#endif/* * Write the contents of the ARP cache to a PROCfs file. */#ifdef CONFIG_PROC_FS#define HBUFFERLEN 30int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy){ int len=0; off_t pos=0; int size; char hbuffer[HBUFFERLEN]; int i,j,k; const char hexbuf[] = "0123456789ABCDEF"; size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n"); pos+=size; len+=size; neigh_table_lock(&arp_tbl); for(i=0; i<=NEIGH_HASHMASK; i++) { struct neighbour *n; for (n=arp_tbl.hash_buckets[i]; n; n=n->next) { struct device *dev = n->dev; int hatype = dev->type; /* Do not confuse users "arp -a" with magic entries */ if (!(n->nud_state&~NUD_NOARP)) continue; /* I'd get great pleasure deleting this ugly code. Let's output it in hexadecimal format. "arp" utility will eventually repaired --ANK */#if 1 /* UGLY CODE *//* * Convert hardware address to XX:XX:XX:XX ... form. */#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) strcpy(hbuffer,ax2asc((ax25_address *)n->ha)); else {#endif 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;#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) }#endif#else if ((neigh->nud_state&NUD_VALID) && dev->addr_len) { int j; for (j=0; j < dev->addr_len; j++) sprintf(hbuffer+2*j, "%02x", neigh->ha[j]); } else sprintf(hbuffer, "0");#endif size = sprintf(buffer+len, "%-17s0x%-10x0x%-10x%s", in_ntoa(*(u32*)n->primary_key), hatype, arp_state_to_flags(n), hbuffer); size += sprintf(buffer+len+size, " %-17s %s\n", "*", dev->name); len += size; pos += size; if (pos <= offset) len=0; if (pos >= offset+length) goto done; } } for (i=0; i<=PNEIGH_HASHMASK; i++) { struct pneigh_entry *n; for (n=arp_tbl.phash_buckets[i]; n; n=n->next) { struct device *dev = n->dev; int hatype = dev ? dev->type : 0; size = sprintf(buffer+len, "%-17s0x%-10x0x%-10x%s", in_ntoa(*(u32*)n->key), hatype, ATF_PUBL|ATF_PERM, "00:00:00:00:00:00"); size += sprintf(buffer+len+size, " %-17s %s\n", "*", dev ? dev->name : "*"); len += size; pos += size; if (pos <= offset) len=0; if (pos >= offset+length) goto done; } }done: neigh_table_unlock(&arp_tbl); *start = buffer+len-(pos-offset); /* Start of wanted data */ len = pos-offset; /* Start slop */ if (len>length) len = length; /* Ending slop */ if (len<0) len = 0; return len;}#endif/* Note, that it is not on notifier chain. It is necessary, that this routine was called after route cache will be flushed. */void arp_ifdown(struct device *dev){ neigh_ifdown(&arp_tbl, dev);}/* * Called once on startup. */static struct packet_type arp_packet_type ={ __constant_htons(ETH_P_ARP), NULL, /* All devices */ arp_rcv, NULL, NULL};#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry proc_net_arp = { PROC_NET_ARP, 3, "arp", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, arp_get_info};#endif__initfunc(void arp_init (void)){ neigh_table_init(&arp_tbl); dev_add_pack(&arp_packet_type);#ifdef CONFIG_PROC_FS proc_net_register(&proc_net_arp);#endif#ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");#endif}#ifdef CONFIG_AX25_MODULE/* * ax25 -> ASCII conversion */char *ax2asc(ax25_address *a){ static char buf[11]; char c, *s; int n; for (n = 0, s = buf; n < 6; n++) { c = (a->ax25_call[n] >> 1) & 0x7F; if (c != ' ') *s++ = c; } *s++ = '-'; if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { *s++ = '1'; n -= 10; } *s++ = n + '0'; *s++ = '\0'; if (*buf == '\0' || *buf == '-') return "*"; return buf;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -