diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
commit | 0d47952611198ef6b1163f366dc03922d20b1475 (patch) | |
tree | 3d840a3b8c0daef0754707bfb9f5e873b6b1ac13 /libdnet-stripped/src/arp-bsd.c | |
parent | Initial commit. (diff) | |
download | nmap-upstream.tar.xz nmap-upstream.zip |
Adding upstream version 7.94+git20230807.3be01efb1+dfsg.upstream/7.94+git20230807.3be01efb1+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | libdnet-stripped/src/arp-bsd.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/libdnet-stripped/src/arp-bsd.c b/libdnet-stripped/src/arp-bsd.c new file mode 100644 index 0000000..e2beb25 --- /dev/null +++ b/libdnet-stripped/src/arp-bsd.c @@ -0,0 +1,323 @@ +/* + * arp-bsd.c + * + * Copyright (c) 2000 Dug Song <dugsong@monkey.org> + * + * $Id: arp-bsd.c 539 2005-01-23 07:36:54Z dugsong $ + */ + +#include "config.h" + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#ifdef HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif +#ifdef HAVE_STREAMS_ROUTE +#include <sys/stream.h> +#include <sys/stropts.h> +#endif + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "dnet.h" + +struct arp_handle { + int fd; + int seq; +}; + +struct arpmsg { + struct rt_msghdr rtm; + u_char addrs[256]; +}; + +arp_t * +arp_open(void) +{ + arp_t *arp; + + if ((arp = calloc(1, sizeof(*arp))) != NULL) { +#ifdef HAVE_STREAMS_ROUTE + if ((arp->fd = open("/dev/route", O_RDWR, 0)) < 0) +#else + if ((arp->fd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) +#endif + return (arp_close(arp)); + } + return (arp); +} + +static int +arp_msg(arp_t *arp, struct arpmsg *msg) +{ + struct arpmsg smsg; + int len, i = 0; + pid_t pid; + + msg->rtm.rtm_version = RTM_VERSION; + msg->rtm.rtm_seq = ++arp->seq; + memcpy(&smsg, msg, sizeof(smsg)); + +#ifdef HAVE_STREAMS_ROUTE + return (ioctl(arp->fd, RTSTR_SEND, &msg->rtm)); +#else + if (write(arp->fd, &smsg, smsg.rtm.rtm_msglen) < 0) { + if (errno != ESRCH || msg->rtm.rtm_type != RTM_DELETE) + return (-1); + } + pid = getpid(); + + /* XXX - should we only read RTM_GET responses here? */ + while ((len = read(arp->fd, msg, sizeof(*msg))) > 0) { + if (len < (int)sizeof(msg->rtm)) + return (-1); + + if (msg->rtm.rtm_pid == pid) { + if (msg->rtm.rtm_seq == arp->seq) + break; + continue; + } else if ((i++ % 2) == 0) + continue; + + /* Repeat request. */ + if (write(arp->fd, &smsg, smsg.rtm.rtm_msglen) < 0) { + if (errno != ESRCH || msg->rtm.rtm_type != RTM_DELETE) + return (-1); + } + } + if (len < 0) + return (-1); + + return (0); +#endif +} + +int +arp_add(arp_t *arp, const struct arp_entry *entry) +{ + struct arpmsg msg; + struct sockaddr_in *sin; + struct sockaddr *sa; + int index, type; + + if (entry->arp_pa.addr_type != ADDR_TYPE_IP || + entry->arp_ha.addr_type != ADDR_TYPE_ETH) { + errno = EAFNOSUPPORT; + return (-1); + } + sin = (struct sockaddr_in *)msg.addrs; + sa = (struct sockaddr *)(sin + 1); + + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0) + return (-1); + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_GET; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin); + + if (arp_msg(arp, &msg) < 0) + return (-1); + + if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) + + sizeof(*sin) + sizeof(*sa)) { + errno = EADDRNOTAVAIL; + return (-1); + } + if (sin->sin_addr.s_addr == entry->arp_pa.addr_ip) { + if ((msg.rtm.rtm_flags & RTF_LLINFO) == 0 || + (msg.rtm.rtm_flags & RTF_GATEWAY) != 0) { + errno = EADDRINUSE; + return (-1); + } + } + if (sa->sa_family != AF_LINK) { + errno = EADDRNOTAVAIL; + return (-1); + } else { + index = ((struct sockaddr_dl *)sa)->sdl_index; + type = ((struct sockaddr_dl *)sa)->sdl_type; + } + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0 || + addr_ntos(&entry->arp_ha, sa) < 0) + return (-1); + + ((struct sockaddr_dl *)sa)->sdl_index = index; + ((struct sockaddr_dl *)sa)->sdl_type = type; + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_ADD; + msg.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; + msg.rtm.rtm_inits = RTV_EXPIRE; + msg.rtm.rtm_flags = RTF_HOST | RTF_STATIC; +#ifdef HAVE_SOCKADDR_SA_LEN + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sin->sin_len + sa->sa_len; +#else + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin) + sizeof(*sa); +#endif + return (arp_msg(arp, &msg)); +} + +int +arp_delete(arp_t *arp, const struct arp_entry *entry) +{ + struct arpmsg msg; + struct sockaddr_in *sin; + struct sockaddr *sa; + + if (entry->arp_pa.addr_type != ADDR_TYPE_IP) { + errno = EAFNOSUPPORT; + return (-1); + } + sin = (struct sockaddr_in *)msg.addrs; + sa = (struct sockaddr *)(sin + 1); + + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0) + return (-1); + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_GET; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin); + + if (arp_msg(arp, &msg) < 0) + return (-1); + + if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) + + sizeof(*sin) + sizeof(*sa)) { + errno = ESRCH; + return (-1); + } + if (sin->sin_addr.s_addr == entry->arp_pa.addr_ip) { + if ((msg.rtm.rtm_flags & RTF_LLINFO) == 0 || + (msg.rtm.rtm_flags & RTF_GATEWAY) != 0) { + errno = EADDRINUSE; + return (-1); + } + } + if (sa->sa_family != AF_LINK) { + errno = ESRCH; + return (-1); + } + msg.rtm.rtm_type = RTM_DELETE; + + return (arp_msg(arp, &msg)); +} + +int +arp_get(arp_t *arp, struct arp_entry *entry) +{ + struct arpmsg msg; + struct sockaddr_in *sin; + struct sockaddr *sa; + + if (entry->arp_pa.addr_type != ADDR_TYPE_IP) { + errno = EAFNOSUPPORT; + return (-1); + } + sin = (struct sockaddr_in *)msg.addrs; + sa = (struct sockaddr *)(sin + 1); + + if (addr_ntos(&entry->arp_pa, (struct sockaddr *)sin) < 0) + return (-1); + + memset(&msg.rtm, 0, sizeof(msg.rtm)); + msg.rtm.rtm_type = RTM_GET; + msg.rtm.rtm_addrs = RTA_DST; + msg.rtm.rtm_flags = RTF_LLINFO; + msg.rtm.rtm_msglen = sizeof(msg.rtm) + sizeof(*sin); + + if (arp_msg(arp, &msg) < 0) + return (-1); + + if (msg.rtm.rtm_msglen < (int)sizeof(msg.rtm) + + sizeof(*sin) + sizeof(*sa) || + sin->sin_addr.s_addr != entry->arp_pa.addr_ip || + sa->sa_family != AF_LINK) { + errno = ESRCH; + return (-1); + } + if (addr_ston(sa, &entry->arp_ha) < 0) + return (-1); + + return (0); +} + +#ifdef HAVE_SYS_SYSCTL_H +int +arp_loop(arp_t *arp, arp_handler callback, void *arg) +{ + struct arp_entry entry; + struct rt_msghdr *rtm; + struct sockaddr_in *sin; + struct sockaddr *sa; + char *buf, *lim, *next; + size_t len; + int ret, mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, + NET_RT_FLAGS, RTF_LLINFO }; + + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) + return (-1); + + if (len == 0) + return (0); + + if ((buf = malloc(len)) == NULL) + return (-1); + + if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) { + free(buf); + return (-1); + } + lim = buf + len; + ret = 0; + + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_in *)(rtm + 1); + sa = (struct sockaddr *)(sin + 1); + + if (addr_ston((struct sockaddr *)sin, &entry.arp_pa) < 0 || + addr_ston(sa, &entry.arp_ha) < 0) + continue; + + if ((ret = callback(&entry, arg)) != 0) + break; + } + free(buf); + + return (ret); +} +#else +int +arp_loop(arp_t *arp, arp_handler callback, void *arg) +{ + errno = ENOSYS; + return (-1); +} +#endif + +arp_t * +arp_close(arp_t *arp) +{ + if (arp != NULL) { + if (arp->fd >= 0) + close(arp->fd); + free(arp); + } + return (NULL); +} |