1
0
mirror of https://github.com/nmap/nmap.git synced 2026-01-10 16:39:04 +00:00
Files
nmap/libdnet-stripped/src/addr.c
dmiller 14c40b6281 Handle AppleTalk devices
Fixed a bug that prevented Nmap from finding any interfaces when one
of them had the type ARP_HDR_APPLETALK; this was the case for
AppleTalk interfaces. However, This support is not complete
since AppleTalk interfaces use different size hardware addresses
than Ethernet. Nmap IP level scans should work without any problem,
please refer to the '--send-ip' switch and to the following thread:
http://seclists.org/nmap-dev/2013/q1/214
This bug was reported by Steven Gregory Johnson on IRC.
2013-02-14 23:32:52 +00:00

483 lines
10 KiB
C

/*
* addr.c
*
* Network address operations.
*
* Copyright (c) 2000 Dug Song <dugsong@monkey.org>
*
* $Id: addr.c 610 2005-06-26 18:23:26Z dugsong $
*/
#ifdef WIN32
#include "dnet_winconfig.h"
#else
#include "config.h"
#endif
#include <sys/types.h>
#ifdef HAVE_NET_IF_H
# include <sys/socket.h>
# include <net/if.h>
#endif
#ifdef HAVE_NET_IF_DL_H
# include <net/if_dl.h>
#endif
#ifdef HAVE_NET_RAW_H
# include <net/raw.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dnet.h"
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 256
#endif
union sockunion {
#ifdef HAVE_NET_IF_DL_H
struct sockaddr_dl sdl;
#endif
struct sockaddr_in sin;
#ifdef HAVE_SOCKADDR_IN6
struct sockaddr_in6 sin6;
#endif
struct sockaddr sa;
#ifdef AF_RAW
struct sockaddr_raw sr;
#endif
};
int
addr_cmp(const struct addr *a, const struct addr *b)
{
int i, j, k;
/* XXX */
if ((i = a->addr_type - b->addr_type) != 0)
return (i);
/* XXX - 10.0.0.1 is "smaller" than 10.0.0.0/8? */
if ((i = a->addr_bits - b->addr_bits) != 0)
return (i);
j = b->addr_bits / 8;
for (i = 0; i < j; i++) {
if ((k = a->addr_data8[i] - b->addr_data8[i]) != 0)
return (k);
}
if ((k = b->addr_bits % 8) == 0)
return (0);
k = ~0 << (8 - k);
i = b->addr_data8[j] & k;
j = a->addr_data8[j] & k;
return (j - i);
}
int
addr_net(const struct addr *a, struct addr *b)
{
uint32_t mask;
int i, j;
if (a->addr_type == ADDR_TYPE_IP) {
addr_btom(a->addr_bits, &mask, IP_ADDR_LEN);
b->addr_type = ADDR_TYPE_IP;
b->addr_bits = IP_ADDR_BITS;
b->addr_ip = a->addr_ip & mask;
} else if (a->addr_type == ADDR_TYPE_ETH) {
memcpy(b, a, sizeof(*b));
if (a->addr_data8[0] & 0x1)
memset(b->addr_data8 + 3, 0, 3);
b->addr_bits = ETH_ADDR_BITS;
} else if (a->addr_type == ADDR_TYPE_IP6) {
b->addr_type = ADDR_TYPE_IP6;
b->addr_bits = IP6_ADDR_BITS;
memset(&b->addr_ip6, 0, IP6_ADDR_LEN);
switch ((i = a->addr_bits / 32)) {
case 4: b->addr_data32[3] = a->addr_data32[3];
case 3: b->addr_data32[2] = a->addr_data32[2];
case 2: b->addr_data32[1] = a->addr_data32[1];
case 1: b->addr_data32[0] = a->addr_data32[0];
}
if ((j = a->addr_bits % 32) > 0) {
addr_btom(j, &mask, sizeof(mask));
b->addr_data32[i] = a->addr_data32[i] & mask;
}
} else
return (-1);
return (0);
}
int
addr_bcast(const struct addr *a, struct addr *b)
{
struct addr mask;
if (a->addr_type == ADDR_TYPE_IP) {
addr_btom(a->addr_bits, &mask.addr_ip, IP_ADDR_LEN);
b->addr_type = ADDR_TYPE_IP;
b->addr_bits = IP_ADDR_BITS;
b->addr_ip = (a->addr_ip & mask.addr_ip) |
(~0L & ~mask.addr_ip);
} else if (a->addr_type == ADDR_TYPE_ETH) {
b->addr_type = ADDR_TYPE_ETH;
b->addr_bits = ETH_ADDR_BITS;
memcpy(&b->addr_eth, ETH_ADDR_BROADCAST, ETH_ADDR_LEN);
} else {
/* XXX - no broadcast addresses in IPv6 */
errno = EINVAL;
return (-1);
}
return (0);
}
char *
addr_ntop(const struct addr *src, char *dst, size_t size)
{
if (src->addr_type == ADDR_TYPE_IP && size >= 20) {
if (ip_ntop(&src->addr_ip, dst, size) != NULL) {
if (src->addr_bits != IP_ADDR_BITS)
sprintf(dst + strlen(dst), "/%d",
src->addr_bits);
return (dst);
}
} else if (src->addr_type == ADDR_TYPE_IP6 && size >= 42) {
if (ip6_ntop(&src->addr_ip6, dst, size) != NULL) {
if (src->addr_bits != IP6_ADDR_BITS)
sprintf(dst + strlen(dst), "/%d",
src->addr_bits);
return (dst);
}
} else if (src->addr_type == ADDR_TYPE_ETH && size >= 18) {
if (src->addr_bits == ETH_ADDR_BITS)
return (eth_ntop(&src->addr_eth, dst, size));
}
errno = EINVAL;
return (NULL);
}
int
addr_pton(const char *src, struct addr *dst)
{
struct hostent *hp;
char *ep, tmp[300];
long bits = -1;
int i;
for (i = 0; i < (int)sizeof(tmp) - 1; i++) {
if (src[i] == '/') {
tmp[i] = '\0';
if (strchr(&src[i + 1], '.')) {
uint32_t m;
uint16_t b;
/* XXX - mask is specified like /255.0.0.0 */
if (ip_pton(&src[i + 1], &m) != 0) {
errno = EINVAL;
return (-1);
}
addr_mtob(&m, sizeof(m), &b);
bits = b;
} else {
bits = strtol(&src[i + 1], &ep, 10);
if (ep == src || *ep != '\0' || bits < 0) {
errno = EINVAL;
return (-1);
}
}
break;
} else if ((tmp[i] = src[i]) == '\0')
break;
}
if (ip_pton(tmp, &dst->addr_ip) == 0) {
dst->addr_type = ADDR_TYPE_IP;
dst->addr_bits = IP_ADDR_BITS;
} else if (eth_pton(tmp, &dst->addr_eth) == 0) {
dst->addr_type = ADDR_TYPE_ETH;
dst->addr_bits = ETH_ADDR_BITS;
} else if (ip6_pton(tmp, &dst->addr_ip6) == 0) {
dst->addr_type = ADDR_TYPE_IP6;
dst->addr_bits = IP6_ADDR_BITS;
} else if ((hp = gethostbyname(tmp)) != NULL) {
memcpy(&dst->addr_ip, hp->h_addr, IP_ADDR_LEN);
dst->addr_type = ADDR_TYPE_IP;
dst->addr_bits = IP_ADDR_BITS;
} else {
errno = EINVAL;
return (-1);
}
if (bits >= 0) {
if (bits > dst->addr_bits) {
errno = EINVAL;
return (-1);
}
dst->addr_bits = (uint16_t)bits;
}
return (0);
}
char *
addr_ntoa(const struct addr *a)
{
static char *p, buf[BUFSIZ];
char *q = NULL;
if (p == NULL || p > buf + sizeof(buf) - 64 /* XXX */)
p = buf;
if (addr_ntop(a, p, (buf + sizeof(buf)) - p) != NULL) {
q = p;
p += strlen(p) + 1;
}
return (q);
}
int
addr_ntos(const struct addr *a, struct sockaddr *sa)
{
union sockunion *so = (union sockunion *)sa;
switch (a->addr_type) {
case ADDR_TYPE_ETH:
#ifdef HAVE_NET_IF_DL_H
memset(&so->sdl, 0, sizeof(so->sdl));
# ifdef HAVE_SOCKADDR_SA_LEN
so->sdl.sdl_len = sizeof(so->sdl);
# endif
# ifdef AF_LINK
so->sdl.sdl_family = AF_LINK;
# else
so->sdl.sdl_family = AF_UNSPEC;
# endif
so->sdl.sdl_alen = ETH_ADDR_LEN;
memcpy(LLADDR(&so->sdl), &a->addr_eth, ETH_ADDR_LEN);
#else
memset(sa, 0, sizeof(*sa));
# ifdef AF_LINK
sa->sa_family = AF_LINK;
# else
sa->sa_family = AF_UNSPEC;
# endif
memcpy(sa->sa_data, &a->addr_eth, ETH_ADDR_LEN);
#endif
break;
#ifdef HAVE_SOCKADDR_IN6
case ADDR_TYPE_IP6:
memset(&so->sin6, 0, sizeof(so->sin6));
#ifdef HAVE_SOCKADDR_SA_LEN
so->sin6.sin6_len = sizeof(so->sin6);
#endif
so->sin6.sin6_family = AF_INET6;
memcpy(&so->sin6.sin6_addr, &a->addr_ip6, IP6_ADDR_LEN);
break;
#endif
case ADDR_TYPE_IP:
memset(&so->sin, 0, sizeof(so->sin));
#ifdef HAVE_SOCKADDR_SA_LEN
so->sin.sin_len = sizeof(so->sin);
#endif
so->sin.sin_family = AF_INET;
so->sin.sin_addr.s_addr = a->addr_ip;
break;
default:
errno = EINVAL;
return (-1);
}
return (0);
}
int
addr_ston(const struct sockaddr *sa, struct addr *a)
{
union sockunion *so = (union sockunion *)sa;
memset(a, 0, sizeof(*a));
switch (sa->sa_family) {
#ifdef HAVE_NET_IF_DL_H
# ifdef AF_LINK
case AF_LINK:
if (so->sdl.sdl_alen != ETH_ADDR_LEN) {
errno = EINVAL;
return (-1);
}
a->addr_type = ADDR_TYPE_ETH;
a->addr_bits = ETH_ADDR_BITS;
memcpy(&a->addr_eth, LLADDR(&so->sdl), ETH_ADDR_LEN);
break;
# endif
#endif
case AF_UNSPEC:
case ARP_HRD_ETH: /* XXX- Linux arp(7) */
case ARP_HRD_APPLETALK: /* AppleTalk DDP */
case ARP_HRD_INFINIBAND: /* InfiniBand */
case ARP_HDR_IEEE80211: /* IEEE 802.11 */
case ARP_HRD_IEEE80211_RADIOTAP: /* IEEE 802.11 + radiotap header */
a->addr_type = ADDR_TYPE_ETH;
a->addr_bits = ETH_ADDR_BITS;
memcpy(&a->addr_eth, sa->sa_data, ETH_ADDR_LEN);
break;
#ifdef AF_RAW
case AF_RAW: /* XXX - IRIX raw(7f) */
a->addr_type = ADDR_TYPE_ETH;
a->addr_bits = ETH_ADDR_BITS;
memcpy(&a->addr_eth, so->sr.sr_addr, ETH_ADDR_LEN);
break;
#endif
#ifdef HAVE_SOCKADDR_IN6
case AF_INET6:
a->addr_type = ADDR_TYPE_IP6;
a->addr_bits = IP6_ADDR_BITS;
memcpy(&a->addr_ip6, &so->sin6.sin6_addr, IP6_ADDR_LEN);
break;
#endif
case AF_INET:
a->addr_type = ADDR_TYPE_IP;
a->addr_bits = IP_ADDR_BITS;
a->addr_ip = so->sin.sin_addr.s_addr;
break;
case ARP_HRD_VOID:
memset(&a->addr_eth, 0, ETH_ADDR_LEN);
break;
default:
errno = EINVAL;
return (-1);
}
return (0);
}
int
addr_btos(uint16_t bits, struct sockaddr *sa)
{
union sockunion *so = (union sockunion *)sa;
#ifdef HAVE_SOCKADDR_IN6
if (bits > IP_ADDR_BITS && bits <= IP6_ADDR_BITS) {
memset(&so->sin6, 0, sizeof(so->sin6));
#ifdef HAVE_SOCKADDR_SA_LEN
so->sin6.sin6_len = IP6_ADDR_LEN + (bits / 8) + (bits % 8);
#endif
so->sin6.sin6_family = AF_INET6;
return (addr_btom(bits, &so->sin6.sin6_addr, IP6_ADDR_LEN));
} else
#endif
if (bits <= IP_ADDR_BITS) {
memset(&so->sin, 0, sizeof(so->sin));
#ifdef HAVE_SOCKADDR_SA_LEN
so->sin.sin_len = IP_ADDR_LEN + (bits / 8) + (bits % 8);
#endif
so->sin.sin_family = AF_INET;
return (addr_btom(bits, &so->sin.sin_addr, IP_ADDR_LEN));
}
errno = EINVAL;
return (-1);
}
int
addr_stob(const struct sockaddr *sa, uint16_t *bits)
{
union sockunion *so = (union sockunion *)sa;
int i, j, len;
uint16_t n;
u_char *p;
#ifdef HAVE_SOCKADDR_IN6
if (sa->sa_family == AF_INET6) {
len = IP6_ADDR_LEN;
p = (u_char *)&so->sin6.sin6_addr;
} else
#endif
{
p = (u_char *)&so->sin.sin_addr.s_addr;
#ifdef HAVE_SOCKADDR_SA_LEN
len = sa->sa_len - ((void *) p - (void *) sa);
/* Handles the special case of sa->sa_len == 0. */
if (len < 0)
len = 0;
else if (len > IP_ADDR_LEN)
len = IP_ADDR_LEN;
#else
len = IP_ADDR_LEN;
#endif
}
for (n = i = 0; i < len; i++, n += 8) {
if (p[i] != 0xff)
break;
}
if (i != len && p[i]) {
for (j = 7; j > 0; j--, n++) {
if ((p[i] & (1 << j)) == 0)
break;
}
}
*bits = n;
return (0);
}
int
addr_btom(uint16_t bits, void *mask, size_t size)
{
int net, host;
u_char *p;
if (size == IP_ADDR_LEN) {
if (bits > IP_ADDR_BITS) {
errno = EINVAL;
return (-1);
}
*(uint32_t *)mask = bits ?
htonl(~0 << (IP_ADDR_BITS - bits)) : 0;
} else {
if (size * 8 < bits) {
errno = EINVAL;
return (-1);
}
p = (u_char *)mask;
if ((net = bits / 8) > 0)
memset(p, 0xff, net);
if ((host = bits % 8) > 0) {
p[net] = 0xff << (8 - host);
memset(&p[net + 1], 0, size - net - 1);
} else
memset(&p[net], 0, size - net);
}
return (0);
}
int
addr_mtob(const void *mask, size_t size, uint16_t *bits)
{
uint16_t n;
u_char *p;
int i, j;
p = (u_char *)mask;
for (n = i = 0; i < (int)size; i++, n += 8) {
if (p[i] != 0xff)
break;
}
if (i != (int)size && p[i]) {
for (j = 7; j > 0; j--, n++) {
if ((p[i] & (1 << j)) == 0)
break;
}
}
*bits = n;
return (0);
}