1
0
mirror of https://github.com/nmap/nmap.git synced 2026-02-07 22:16:33 +00:00
Files
nmap/libdnet-stripped/src/addr.c
david 48ff61a710 Handle ARPHRD_VOID in addr_ston.
This type is used by OpenVZ venet interfaces. We "handle" such an
address type just by blanking the MAC address field.

Lack of support for this type of interface was preventing Nmap from
working on certain systems.

http://seclists.org/nmap-dev/2012/q2/763

An earlier message about this same type of interface is

http://seclists.org/nmap-dev/2009/q3/303
2012-07-21 07:35:41 +00:00

480 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_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);
}