/* * Builds and sends a single ARP request to locate the server * * Return value: * 0 on success * errno on error */ static int netdump_send_arp(in_addr_t dst) { struct ether_addr bcast; struct mbuf *m; struct arphdr *ah; int pktlen; MPASS(nd_ifp != NULL); /* Fill-up a broadcast address. */ memset(&bcast, 0xFF, ETHER_ADDR_LEN); m = m_gethdr(M_NOWAIT, MT_DATA); if (m == NULL) { printf("netdump_send_arp: Out of mbufs\n"); return (ENOBUFS); } pktlen = arphdr_len2(ETHER_ADDR_LEN, sizeof(struct in_addr)); m->m_len = pktlen; m->m_pkthdr.len = pktlen; MH_ALIGN(m, pktlen); ah = mtod(m, struct arphdr *); ah->ar_hrd = htons(ARPHRD_ETHER); ah->ar_pro = htons(ETHERTYPE_IP); ah->ar_hln = ETHER_ADDR_LEN; ah->ar_pln = sizeof(struct in_addr); ah->ar_op = htons(ARPOP_REQUEST); memcpy(ar_sha(ah), IF_LLADDR(nd_ifp), ETHER_ADDR_LEN); ((struct in_addr *)ar_spa(ah))->s_addr = nd_client.s_addr; bzero(ar_tha(ah), ETHER_ADDR_LEN); ((struct in_addr *)ar_tpa(ah))->s_addr = dst; return (netdump_ether_output(m, nd_ifp, bcast, ETHERTYPE_ARP)); }
static int send_arp (interface_t *iface, int op, struct in_addr sip, unsigned char *taddr, struct in_addr tip) { struct arphdr *arp; int arpsize = arphdr_len2 (iface->hwlen, sizeof (struct in_addr)); int retval; arp = xmalloc (arpsize); memset (arp, 0, arpsize); arp->ar_hrd = htons (iface->family); arp->ar_pro = htons (ETHERTYPE_IP); arp->ar_hln = iface->hwlen; arp->ar_pln = sizeof (struct in_addr); arp->ar_op = htons (op); memcpy (ar_sha (arp), &iface->hwaddr, arp->ar_hln); memcpy (ar_spa (arp), &sip, arp->ar_pln); if (taddr) memcpy (ar_tha (arp), taddr, arp->ar_hln); memcpy (ar_tpa (arp), &tip, arp->ar_pln); retval = send_packet (iface, ETHERTYPE_ARP, (unsigned char *) arp, arphdr_len (arp)); free (arp); return (retval); }
int arp_check (interface_t *iface, struct in_addr address) { if (! iface->arpable) { logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable", iface->name); return 0; } unsigned char buf[256]; struct arphdr *ah = (struct arphdr *) buf; memset (buf, 0, sizeof (buf)); ah->ar_hrd = htons (ARPHRD_ETHER); ah->ar_pro = htons (ETHERTYPE_IP); ah->ar_hln = ETHER_ADDR_LEN; ah->ar_pln = sizeof (struct in_addr); ah->ar_op = htons (ARPOP_REQUEST); memcpy (ar_sha (ah), &iface->ethernet_address, ah->ar_hln); memcpy (ar_tpa (ah), &address, ah->ar_pln); logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa (address)); open_socket (iface, true); send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &buf, arphdr_len(ah)); unsigned char reply[4096]; int bytes; unsigned char buffer[iface->buffer_length]; struct timeval tv; long timeout = 0; fd_set rset; timeout = uptime() + TIMEOUT; while (1) { tv.tv_sec = timeout - uptime (); tv.tv_usec = 0; if (tv.tv_sec < 1) break; /* Time out */ FD_ZERO (&rset); FD_SET (iface->fd, &rset); if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0) break; if (! FD_ISSET (iface->fd, &rset)) continue; memset (buffer, 0, sizeof (buffer)); int buflen = sizeof (buffer); int bufpos = -1; while (bufpos != 0) { memset (reply, 0, sizeof (reply)); if ((bytes = get_packet (iface, (unsigned char *) &reply, buffer, &buflen, &bufpos)) < 0) break; ah = (struct arphdr *) reply; /* Only these types are recognised */ if (ah->ar_op != htons(ARPOP_REPLY) || ah->ar_hrd != htons (ARPHRD_ETHER)) continue; /* Protocol must be IP. */ if (ah->ar_pro != htons (ETHERTYPE_IP)) continue; if (ah->ar_pln != sizeof (struct in_addr)) continue; if (ah->ar_hln != ETHER_ADDR_LEN) continue; if (bytes < sizeof (*ah) + 2 * (4 + ah->ar_hln)) continue; logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", inet_ntoa (* (struct in_addr *) ar_spa (ah)), ether_ntoa ((struct ether_addr *) ar_sha (ah))); close (iface->fd); iface->fd = -1; return 1; } } close (iface->fd); iface->fd = -1; return 0; }
int arp_check (interface_t *iface, struct in_addr address) { union { unsigned char buffer[iface->buffer_length]; struct arphdr ah; } arp; int bytes; struct timeval tv; long timeout = 0; fd_set rset; if (! iface->arpable) { logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable", iface->name); return 0; } memset (arp.buffer, 0, sizeof (arp.buffer)); arp.ah.ar_hrd = htons (iface->family); arp.ah.ar_pro = htons (ETHERTYPE_IP); arp.ah.ar_hln = iface->hwlen; arp.ah.ar_pln = sizeof (struct in_addr); arp.ah.ar_op = htons (ARPOP_REQUEST); memcpy (ar_sha (&arp.ah), &iface->hwaddr, arp.ah.ar_hln); memcpy (ar_tpa (&arp.ah), &address, arp.ah.ar_pln); logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa (address)); open_socket (iface, true); send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &arp.buffer, arphdr_len (&arp.ah)); timeout = uptime() + TIMEOUT; while (1) { int buflen = sizeof (arp.buffer); int bufpos = -1; tv.tv_sec = timeout - uptime (); tv.tv_usec = 0; if (tv.tv_sec < 1) break; /* Time out */ FD_ZERO (&rset); FD_SET (iface->fd, &rset); if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0) break; if (! FD_ISSET (iface->fd, &rset)) continue; memset (arp.buffer, 0, sizeof (arp.buffer)); while (bufpos != 0) { union { unsigned char buffer[buflen]; struct arphdr hdr; } reply; union { unsigned char *c; struct in_addr *a; } rp; union { unsigned char *c; struct ether_addr *a; } rh; memset (reply.buffer, 0, sizeof (reply.buffer)); if ((bytes = get_packet (iface, reply.buffer, arp.buffer, &buflen, &bufpos)) < 0) break; /* Only these types are recognised */ if (reply.hdr.ar_op != htons(ARPOP_REPLY)) continue; /* Protocol must be IP. */ if (reply.hdr.ar_pro != htons (ETHERTYPE_IP)) continue; if (reply.hdr.ar_pln != sizeof (struct in_addr)) continue; if (reply.hdr.ar_hln != ETHER_ADDR_LEN) continue; if ((unsigned) bytes < sizeof (reply.hdr) + 2 * (4 + reply.hdr.ar_hln)) continue; rp.c = (unsigned char *) ar_spa (&reply.hdr); rh.c = (unsigned char *) ar_sha (&reply.hdr); logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", inet_ntoa (*rp.a), ether_ntoa (rh.a)); close (iface->fd); iface->fd = -1; return 1; } } close (iface->fd); iface->fd = -1; return 0; }
int arp_claim (interface_t *iface, struct in_addr address) { struct arphdr *reply = NULL; long timeout = 0; unsigned char *buffer; int retval = -1; int nprobes = 0; int nclaims = 0; struct in_addr null_address; if (! iface->arpable) { logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); return (0); } logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa (address)); if (! open_socket (iface, true)) return (0); memset (&null_address, 0, sizeof (null_address)); buffer = xmalloc (sizeof (char *) * iface->buffer_length); /* Our ARP packets are always smaller - hopefully */ reply = xmalloc (IP_MIN_FRAME_LENGTH); while (1) { struct timeval tv; int bufpos = -1; int buflen = sizeof (char *) * iface->buffer_length; fd_set rset; int bytes; int s; tv.tv_sec = 0; tv.tv_usec = timeout; FD_ZERO (&rset); FD_SET (iface->fd, &rset); errno = 0; if ((s = select (FD_SETSIZE, &rset, NULL, NULL, &tv)) == -1) { if (errno != EINTR) logger (LOG_ERR, "select: `%s'", strerror (errno)); break; } else if (s == 0) { /* Timed out */ if (nprobes < NPROBES) { nprobes ++; timeout = PROBE_INTERVAL; logger (LOG_DEBUG, "sending ARP probe #%d", nprobes); send_arp (iface, ARPOP_REQUEST, null_address, NULL, address); } else if (nclaims < NCLAIMS) { nclaims ++; timeout = CLAIM_INTERVAL; logger (LOG_DEBUG, "sending ARP claim #%d", nclaims); send_arp (iface, ARPOP_REQUEST, address, iface->hwaddr, address); } else { /* No replies, so done */ retval = 0; break; } } if (! FD_ISSET (iface->fd, &rset)) continue; memset (buffer, 0, buflen); while (bufpos != 0) { union { unsigned char *c; struct in_addr *a; } rp; union { unsigned char *c; struct ether_addr *a; } rh; memset (reply, 0, IP_MIN_FRAME_LENGTH); if ((bytes = get_packet (iface, (unsigned char *) reply, buffer, &buflen, &bufpos)) == -1) break; /* Only these types are recognised */ if (reply->ar_op != htons (ARPOP_REPLY)) continue; /* Protocol must be IP. */ if (reply->ar_pro != htons (ETHERTYPE_IP)) continue; if (reply->ar_pln != sizeof (struct in_addr)) continue; if ((unsigned) bytes < sizeof (reply) + 2 * (4 + reply->ar_hln)) continue; rp.c = (unsigned char *) ar_spa (reply); rh.c = (unsigned char *) ar_sha (reply); /* Ensure the ARP reply is for the address we asked for */ if (rp.a->s_addr != address.s_addr) continue; /* Some systems send a reply back from our hwaddress - weird */ if (reply->ar_hln == iface->hwlen && memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) continue; logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", inet_ntoa (*rp.a), hwaddr_ntoa (rh.c, reply->ar_hln)); retval = -1; goto eexit; } } eexit: close (iface->fd); iface->fd = -1; free (buffer); free (reply); return (retval); }