Logo Search packages:      
Sourcecode: nmap version File versions

addr.c

/*
 * addr.c
 *
 * Network address operations.
 *
 * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
 *
 * $Id: addr.c,v 1.33 2005/01/23 07:36:54 dugsong Exp $
 */

#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
            so->sdl.sdl_family = AF_LINK;
            so->sdl.sdl_alen = ETH_ADDR_LEN;
            memcpy(LLADDR(&so->sdl), &a->addr_eth, ETH_ADDR_LEN);
#else
            memset(sa, 0, sizeof(*sa));
            sa->sa_family = AF_UNSPEC;
            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
      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
      case AF_UNSPEC:
      case ARP_HRD_ETH: /* XXX- Linux arp(7) */
            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;
      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
      {
#ifdef HAVE_SOCKADDR_SA_LEN
            if ((len = sa->sa_len - IP_ADDR_LEN) > IP_ADDR_LEN)
#endif
            len = IP_ADDR_LEN;
            p = (u_char *)&so->sin.sin_addr.s_addr;
      }
      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);
}

Generated by  Doxygen 1.6.0   Back to index