Example #1
0
int net_ipv6_send(netif_t *net, const uint8 *data, size_t data_size,
                  int hop_limit, int proto, const struct in6_addr *src,
                  const struct in6_addr *dst) {
    ipv6_hdr_t hdr;

    if(!net) {
        net = net_default_dev;

        if(!net) {
            errno = ENETDOWN;
            return -1;
        }
    }

    /* Set up the hop limit. We need to do this here, in case we end up passing
       this off to the IPv4 code, otherwise we could end up with a 0 down there
       for the ttl, which would be bad. */
    if(!hop_limit) {
        if(net->hop_limit)
            hop_limit = net->hop_limit;
        else
            hop_limit = 255;
    }

    /* If this is actually going both to and from an IPv4 address, use the IPv4
       send function to do the rest. Note that only V4-mapped addresses are
       supported here (::ffff:x.y.z.w) */
    if(IN6_IS_ADDR_V4MAPPED(src) && IN6_IS_ADDR_V4MAPPED(dst)) {
        return net_ipv4_send(net, data, data_size, -1, hop_limit, proto,
                             src->__s6_addr.__s6_addr32[3],
                             dst->__s6_addr.__s6_addr32[3]);
    }
    else if(IN6_IS_ADDR_V4MAPPED(src) || IN6_IS_ADDR_V4MAPPED(dst) ||
            IN6_IS_ADDR_V4COMPAT(src) || IN6_IS_ADDR_V4COMPAT(dst)) {
        return -1;
    }

    hdr.version_lclass = 0x60;
    hdr.hclass_lflow = 0;
    hdr.lclass = 0;
    hdr.length = ntohs(data_size);
    hdr.next_header = proto;
    hdr.hop_limit = hop_limit;
    hdr.src_addr = *src;
    hdr.dst_addr = *dst;

    /* XXXX: Handle fragmentation... */
    return net_ipv6_send_packet(net, &hdr, data, data_size);
}
Example #2
0
void
server_unicast_option(dhcp_smach_t *dsmp, PKT_LIST *plp)
{
	const dhcpv6_option_t *d6o;
	uint_t olen;

	d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_UNICAST, &olen);
	olen -= sizeof (*d6o);
	/* LINTED: no consequent */
	if (d6o == NULL) {
		/* No Server Unicast option specified */
	} else if (olen != sizeof (dsmp->dsm_server)) {
		dhcpmsg(MSG_WARNING, "server_unicast_option: %s has Server "
		    "Unicast option with bad length",
		    pkt_type_to_string(pkt_recv_type(plp), B_TRUE));
	} else {
		in6_addr_t addr;

		(void) memcpy(&addr, d6o + 1, olen);
		if (IN6_IS_ADDR_UNSPECIFIED(&addr)) {
			dhcpmsg(MSG_WARNING, "server_unicast_option: unicast "
			    "to unspecified address ignored");
		} else if (IN6_IS_ADDR_MULTICAST(&addr)) {
			dhcpmsg(MSG_WARNING, "server_unicast_option: unicast "
			    "to multicast address ignored");
		} else if (IN6_IS_ADDR_V4COMPAT(&addr) ||
		    IN6_IS_ADDR_V4MAPPED(&addr)) {
			dhcpmsg(MSG_WARNING, "server_unicast_option: unicast "
			    "to invalid address ignored");
		} else {
			dsmp->dsm_server = addr;
		}
	}
}
Example #3
0
// Return the 4-byte IP address, converting it into host byte order.
ACE_UINT32
ACE_INET_Addr::get_ip_address (void) const
{
  ACE_TRACE ("ACE_INET_Addr::get_ip_address");
#if defined (ACE_HAS_IPV6)
  if (this->get_type () == AF_INET6)
    {
      if (IN6_IS_ADDR_V4MAPPED (&this->inet_addr_.in6_.sin6_addr) ||
          IN6_IS_ADDR_V4COMPAT (&this->inet_addr_.in6_.sin6_addr)    )
        {
          ACE_UINT32 addr;
          // Return the last 32 bits of the address
          char *thisaddrptr = (char*)this->ip_addr_pointer ();
          thisaddrptr += 128/8 - 32/8;
          ACE_OS::memcpy (&addr, thisaddrptr, sizeof (addr));
          return ACE_NTOHL (addr);
        }

      ACE_ERROR ((LM_ERROR,
                  ACE_LIB_TEXT ("ACE_INET_Addr::get_ip_address: address is a IPv6 address not IPv4\n")));
      errno = EAFNOSUPPORT;
      return 0;
    }
#endif /* ACE_HAS_IPV6 */
  return ntohl (ACE_UINT32 (this->inet_addr_.in4_.sin_addr.s_addr));
}
Example #4
0
int get_host_addr(void *addr, unsigned int addrlen, const char *host, unsigned short port)
{
	struct addrinfo hint = {0};
	struct addrinfo *addrlink = NULL;
	struct addrinfo *tmp = NULL;
	unsigned short *lpport = (unsigned short *)((char*)addr + 1 + sizeof(unsigned short));
	hint.ai_flags = AI_CANONNAME;

	if(getaddrinfo(host, NULL, &hint, &addrlink) != 0) {
		return -1;
	}

	for(tmp = addrlink; tmp != NULL; tmp = tmp->ai_next) {
		if(tmp->ai_family == AF_INET6) {
			if(IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)tmp->ai_addr)->sin6_addr)
				|| IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)tmp->ai_addr)->sin6_addr)
				|| IN6_IS_ADDR_SITELOCAL(&((struct sockaddr_in6 *)tmp->ai_addr)->sin6_addr)
				|| IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)tmp->ai_addr)->sin6_addr)
				|| IN6_IS_ADDR_V4COMPAT(&((struct sockaddr_in6 *)tmp->ai_addr)->sin6_addr) ) {
				continue;
			}
		} 

		((char*)addr)[0] = (char)(tmp->ai_addrlen > addrlen ? addrlen : tmp->ai_addrlen);
		memcpy((char*)addr+1, tmp->ai_addr, ((char*)addr)[0]);
		*lpport = htons(port);
		break;
	}

	freeaddrinfo(addrlink);
	return 0;
}
Example #5
0
int
isns_portal_to_sockaddr(const isns_portal_info_t *portal,
		struct sockaddr_storage *addr)
{
	const struct sockaddr_in6 *six = &portal->addr;
	struct sockaddr_in *sin;

	/* Check if this is really a v4 address is disguise.
	 * If so, explicitly use an AF_INET socket - the
	 * stack may not support IPv6.
	 */
	if (IN6_IS_ADDR_V4MAPPED(&six->sin6_addr)
	 || IN6_IS_ADDR_V4COMPAT(&six->sin6_addr)) {
		sin = (struct sockaddr_in *) addr;

		memset(sin, 0, sizeof(*sin));
		sin->sin_family = AF_INET;
		sin->sin_addr.s_addr = six->sin6_addr.s6_addr32[3];
		sin->sin_port = six->sin6_port;

		return sizeof(*sin);
	}
	
	/* This is the genuine article */
	memcpy(addr, six, sizeof(*six));
	return sizeof(*six);
}
Example #6
0
/** \brief Convert libnf IP address to string.
 *
 * Without conversion, IP address is converted to
 * UINT[0]:UINT[1]:UINT[2]:UINT[3]. If IPv4 is present, first three UINTs are
 * zero. With conversion, inet_ntop() is used to convert binary representation
 * to string.
 *
 * \param[in] addr Binary IP address representation.
 * \return String IP address representation. Static memory.
 */
static const char * mylnf_addr_to_str(const lnf_ip_t *addr)
{
        const char *ret;

        switch (output_params.ip_addr_conv) {
        case OUTPUT_IP_ADDR_CONV_NONE:
                snprintf(global_str, sizeof (global_str),
                                "%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":%" PRIu32,
                                ntohl(addr->data[0]), ntohl(addr->data[1]),
                                ntohl(addr->data[2]), ntohl(addr->data[3]));
                break;

        case OUTPUT_IP_ADDR_CONV_STR:
                if (IN6_IS_ADDR_V4COMPAT(addr->data)) { //IPv4 compatibile
                        ret = inet_ntop(AF_INET, addr->data + 3, global_str,
                                        INET_ADDRSTRLEN);
                } else { //IPv6
                        ret = inet_ntop(AF_INET6, addr->data, global_str,
                                        INET6_ADDRSTRLEN);
                }
                assert(ret != NULL);

                break;

        default:
                assert(!"unknown IP address conversion");
        }

        return global_str;
}
Example #7
0
bool SocketAddress::isCompatIpv6(void) const
{
	if (AF_INET6 == data_.base_.sa_family)
	{
		return IN6_IS_ADDR_V4COMPAT(&data_.in6_.sin6_addr);
	}
	return false;
}
Example #8
0
/* function for IPv4/IPv6 address */
static void format_addr(char *buff, char *data) {
	lnf_ip_t *addr = (lnf_ip_t *)data;

	if (IN6_IS_ADDR_V4COMPAT((struct in6_addr *)addr)) {
		inet_ntop(AF_INET, (char *)&(addr->data[3]), buff, MAX_STR);
	} else {
		inet_ntop(AF_INET6, addr, buff, MAX_STR);
	}
}
Example #9
0
static krb5_boolean
ipv6_uninteresting (const struct sockaddr *sa)
{
    const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
    const struct in6_addr *in6 = (const struct in6_addr *)&sin6->sin6_addr;

    return
	IN6_IS_ADDR_LINKLOCAL(in6)
	|| IN6_IS_ADDR_V4COMPAT(in6);
}
Example #10
0
 // Constructs an address corresponding to 'ss' that's compatible with 'fd'.
 CompatibleSocketAddress(int fd, const sockaddr_storage& ss, bool mapUnspecified) {
     const int desiredFamily = getSocketAddressFamily(fd);
     if (ss.ss_family == AF_INET6) {
         if (desiredFamily == AF_INET6) {
             // Nothing to do.
             mCompatibleAddress = reinterpret_cast<const sockaddr*>(&ss);
         } else {
             sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(&mTmp);
             const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(&ss);
             memset(sin, 0, sizeof(*sin));
             sin->sin_family = AF_INET;
             sin->sin_port = sin6->sin6_port;
             if (IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr)) {
                 // We have an IPv6-mapped IPv4 address, but need plain old IPv4.
                 // Unmap the mapped address in ss into an IPv6 address in mTmp.
                 memcpy(&sin->sin_addr.s_addr, &sin6->sin6_addr.s6_addr[12], 4);
                 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&mTmp);
             } else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) {
                 // Translate the IPv6 loopback address to the IPv4 one.
                 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
                 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&mTmp);
             } else {
                 // We can't help you. We return what you gave us, and assume you'll
                 // get a sensible error when you use the address.
                 mCompatibleAddress = reinterpret_cast<const sockaddr*>(&ss);
             }
         }
     } else /* ss.ss_family == AF_INET */ {
         if (desiredFamily == AF_INET) {
             // Nothing to do.
             mCompatibleAddress = reinterpret_cast<const sockaddr*>(&ss);
         } else {
             // We have IPv4 and need IPv6.
             // Map the IPv4 address in ss into an IPv6 address in mTmp.
             const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(&ss);
             sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(&mTmp);
             memset(sin6, 0, sizeof(*sin6));
             sin6->sin6_family = AF_INET6;
             sin6->sin6_port = sin->sin_port;
             // TODO: mapUnspecified was introduced because kernels < 2.6.31 don't allow
             // you to bind to ::ffff:0.0.0.0. When we move to something >= 2.6.31, we
             // should make the code behave as if mapUnspecified were always true, and
             // remove the parameter.
             if (sin->sin_addr.s_addr != 0 || mapUnspecified) {
                 memset(&(sin6->sin6_addr.s6_addr[10]), 0xff, 2);
             }
             memcpy(&sin6->sin6_addr.s6_addr[12], &sin->sin_addr.s_addr, 4);
             mCompatibleAddress = reinterpret_cast<const sockaddr*>(&mTmp);
         }
     }
 }
Example #11
0
/** Return IPv6 address scope */
static int
li_scope6(struct in6_addr const *ip6)
{
  if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {
    uint32_t ip4 = *(uint32_t *)(ip6->s6_addr + 12);
    return li_scope4(ip4);
  }
  else if (IN6_IS_ADDR_LOOPBACK(ip6))
    return LI_SCOPE_HOST;
  else if (IN6_IS_ADDR_LINKLOCAL(ip6))
    return LI_SCOPE_LINK;
  else if (IN6_IS_ADDR_SITELOCAL(ip6))
    return LI_SCOPE_SITE;
  else
    return LI_SCOPE_GLOBAL;
}
Example #12
0
/* char *
 * inetntop(af, src, dst, size)
 *	convert a network format address to presentation format.
 * return:
 *	pointer to presentation format address (`dst'), or NULL (see errno).
 * author:
 *	Paul Vixie, 1996.
 */
const char *
inetntop(int af, const void *src, char *dst, unsigned int size)
{
  switch (af)
  {
    case AF_INET:
      return inet_ntop4(src, dst, size);
#ifdef IPV6
    case AF_INET6:
      if (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src) ||
          IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src))
        return inet_ntop4((unsigned char *)&((const struct in6_addr *)src)->s6_addr[12], dst, size);
      else 
        return inet_ntop6(src, dst, size);
#endif
    default:
      return NULL;
  }
  /* NOTREACHED */
}
Example #13
0
const char *
inet_ntop6(const struct in6_addr *addr, char *dst, size_t size)
{
	char hexa[8][5], tmp[MAX_V6_ADDR_LEN];
	int zr[8];
	size_t len;
	int32_t i, j, k, skip;
	uint8_t x8, hx8;
	uint16_t x16;
	struct in_addr a4;
	
	if (addr == NULL) return NULL;
	
	memset(tmp, 0, MAX_V6_ADDR_LEN);
	
	/*  check for mapped or compat addresses */
	i = IN6_IS_ADDR_V4MAPPED(addr);
	j = IN6_IS_ADDR_V4COMPAT(addr);
	if ((i != 0) || (j != 0))
	{
		a4.s_addr = addr->__u6_addr.__u6_addr32[3];
		sprintf(tmp, "::%s%s", (i != 0) ? "ffff:" : "", inet_ntoa(a4));
		len = strlen(tmp) + 1;
		if (len > size) return NULL;
		memcpy(dst, tmp, len);
		return dst;
	}
	
	k = 0;
	for (i = 0; i < 16; i += 2)
	{
		j = 0;
		skip = 1;
		
		memset(hexa[k], 0, 5);
		
		x8 = addr->__u6_addr.__u6_addr8[i];
		
		hx8 = x8 >> 4;
		if (hx8 != 0)
		{
			skip = 0;
			hexa[k][j++] = hexchars[hx8];
		}
		
		hx8 = x8 & 0x0f;
		if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
		{
			skip = 0;
			hexa[k][j++] = hexchars[hx8];
		}
		
		x8 = addr->__u6_addr.__u6_addr8[i + 1];
		
		hx8 = x8 >> 4;
		if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
		{
			hexa[k][j++] = hexchars[hx8];
		}
		
		hx8 = x8 & 0x0f;
		hexa[k][j++] = hexchars[hx8];
		
		k++;
	}
	
	/* find runs of zeros for :: convention */
	j = 0;
	for (i = 7; i >= 0; i--)
	{
		zr[i] = j;
		x16 = addr->__u6_addr.__u6_addr16[i];
		if (x16 == 0) j++;
		else j = 0;
		zr[i] = j;
	}
	
	/* find longest run of zeros */
	k = -1;
	j = 0;
	for(i = 0; i < 8; i++)
	{
		if (zr[i] > j)
		{
			k = i;
			j = zr[i];
		}
	}
	
	for(i = 0; i < 8; i++)
	{
		if (i != k) zr[i] = 0;
	}
	
	len = 0;
	for (i = 0; i < 8; i++)
	{
		if (zr[i] != 0)
		{
			/* check for leading zero */
			if (i == 0) tmp[len++] = ':';
			tmp[len++] = ':';
			i += (zr[i] - 1);
			continue;
		}
		for (j = 0; hexa[i][j] != '\0'; j++) tmp[len++] = hexa[i][j];
		if (i != 7) tmp[len++] = ':';
	}

	/* trailing NULL */
	len++;

	if (len > size) return NULL;
	memcpy(dst, tmp, len);
	return dst;
}
Example #14
0
/** Build a list of local IPv6 addresses and append it to *return_result. */
static
int localinfo6(su_localinfo_t const *hints, su_localinfo_t **return_result)
{
  su_localinfo_t *li = NULL;
  su_sockaddr_t su[1] = {{ 0 }}, *addr;
  int error = ELI_NOADDRESS;
  char *canonname = NULL;
  char line[80];
  FILE *f;

  if ((f = fopen("/proc/net/if_inet6", "r"))) {
    for (;error;) {
      struct in6_addr in6;
      unsigned if_index, prefix_len, scope, flags;
      int addrlen, if_namelen;
      char ifname[16];

      if (!fgets(line, sizeof(line), f)) {
	if (feof(f))
	  error = ELI_NOERROR;
	break;
      }

      if (sscanf(line, "%08x%08x%08x%08x %2x %2x %2x %02x %016s\n",
		 &in6.s6_addr32[0],
		 &in6.s6_addr32[1],
		 &in6.s6_addr32[2],
		 &in6.s6_addr32[3],
		 &if_index, &prefix_len, &scope, &flags, ifname) != 9)
	break;

      flags = 0;

      /* Fix global scope (it is 0) */
      if (!scope) scope = LI_SCOPE_GLOBAL;

      in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
      in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
      in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
      in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);

      if (IN6_IS_ADDR_V4MAPPED(&in6) || IN6_IS_ADDR_V4COMPAT(&in6)) {
	uint32_t ip4 = *(uint32_t *)(in6.s6_addr + 12);
	scope = li_scope4(ip4);
      }

      if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
	  (hints->li_index && hints->li_index != if_index) ||
	  (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0))
	continue;

      su->su_family = AF_INET6;
      su->su_sin6.sin6_addr = in6;

      addrlen = su_sockaddr_size(su);

      if ((error = li_name(hints, 0, su, &canonname)) < 0)
	break;
      else if (error > 0)
	continue;
      else
	error = ELI_NOADDRESS;

      if (canonname &&
	  (strchr(canonname, ':') ||
	   strspn(canonname, "0123456789.") == strlen(canonname)))
	flags |= LI_NUMERIC;

      if (hints->li_flags & LI_IFNAME)
	if_namelen = strlen(ifname) + 1;
      else
	if_namelen = 0;

      if ((li = calloc(1, sizeof *li + addrlen + if_namelen)) == NULL) {
	error = ELI_MEMORY;
	break;
      }
      addr = (su_sockaddr_t*)memcpy((li + 1), su, addrlen);
      *return_result = li; return_result = &li->li_next;

      li->li_flags = flags;
      li->li_family = AF_INET6;
      li->li_scope = scope;
      li->li_index = if_index;
      li->li_addr = addr;
      li->li_addrlen = addrlen;
      li->li_canonname = canonname;
      if (if_namelen)
	li->li_ifname = memcpy(addrlen + (char *)addr, ifname, if_namelen);

      canonname = NULL;
    }

    fclose(f);
  }

  if (canonname)
    free(canonname);

  return error;
}
Example #15
0
/*
 * Get a new connection request and initialize 'cp' appropriately
 */
static status_e get_connection( struct service *sp, connection_s *cp )
{
   struct service_config *scp = SVC_CONF( sp );
   socklen_t sin_len;
   const char *func = "get_connection" ;
   int on = 1;

   if( SC_IPV4(scp) ) sin_len = sizeof(struct sockaddr_in);
   if( SC_IPV6(scp) ) sin_len = sizeof(struct sockaddr_in6);

   if ( SVC_SOCKET_TYPE( sp ) == SOCK_STREAM ) {
      /* If it's a TCP socket, and we're set to wait, the accept is
       * done by the child process.  Don't set NEW_DESCRIPTOR, since
       * there isn't one.  The descriptor will be/was removed from
       * the descriptor set in svc_suspend and re-enabled in svc_resume.
       */
      if( SC_WAITS( scp ) ) {
         cp->co_descriptor = SVC_FD( sp );
      } else {
         cp->co_descriptor = accept( SVC_FD( sp ), &(cp->co_remote_address.sa),
                                     &sin_len ) ;
	 if (cp->co_descriptor != -1)
             M_SET( cp->co_flags, COF_NEW_DESCRIPTOR ) ;
      }

      if ( cp->co_descriptor == -1 )
      {
	 if ((errno == EMFILE) || (errno == ENFILE))
	     cps_service_stop(sp, "no available descriptors");
	 else
             msg( LOG_ERR, func, "service %s, accept: %m", SVC_ID( sp ) ) ;
         return( FAILED ) ;
      }

      if( SC_NODELAY( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) )
         if( setsockopt(SVC_FD(sp), IPPROTO_TCP, TCP_NODELAY, 
                        (char *)&on, sizeof( on ) ) < 0 )
            msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp));

      if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) )
      {
         if( setsockopt(SVC_FD(sp), SOL_SOCKET, SO_KEEPALIVE, 
                        (char *)&on, sizeof( on ) ) < 0 )
            msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp));
      }
      
      if( SC_IPV6(scp) && !(SC_V6ONLY( scp ))  && 
         (IN6_IS_ADDR_V4MAPPED(&cp->co_remote_address.sa_in6.sin6_addr) || 
	  IN6_IS_ADDR_V4COMPAT(&cp->co_remote_address.sa_in6.sin6_addr)) ) 
      {
         int af = AF_INET;
         if( setsockopt(cp->co_descriptor, IPPROTO_IPV6,
               IPV6_ADDRFORM, &af, sizeof( af ) ) ) {
            if( debug.on ) msg( LOG_WARNING, func, "service %s, IPV6_ADDRFORM setsockopt() failed: %m", SVC_ID( sp) );
         }
      }

      M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
   }
   else
   {
      if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM )
      {
         char t_ch ;
	 ssize_t val;

         /*
          * This trick is done to get the remote address.
          * select(2) guaranteed that we won't block on the recvfrom
          */
	 val = recvfrom( SVC_FD( sp ), &t_ch, 1, MSG_PEEK,
                              &cp->co_remote_address.sa, &sin_len );
         if ( val == (ssize_t)-1 )
         {
            msg( LOG_ERR, func, "service %s, recvfrom: %m", SVC_ID( sp ) ) ;
            return( FAILED ) ;
         }
         M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
      }

      cp->co_descriptor = SVC_FD( sp ) ;
   }

   return( OK ) ;
}
Example #16
0
static void
tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
    uint8_t tflags)
{
	char *p, *pp;
	int mask, af;
	struct in6_addr *paddr, tmp;
	struct tflow_entry *tfe;
	uint32_t key, *pkey;
	uint16_t port;
	struct protoent *pent;
	struct servent *sent;
	int masklen;

	masklen = 0;
	af = 0;
	paddr = (struct in6_addr *)&tentry->k;

	switch (type) {
	case IPFW_TABLE_ADDR:
		/* Remove / if exists */
		if ((p = strchr(arg, '/')) != NULL) {
			*p = '\0';
			mask = atoi(p + 1);
		}

		if (inet_pton(AF_INET, arg, paddr) == 1) {
			if (p != NULL && mask > 32)
				errx(EX_DATAERR, "bad IPv4 mask width: %s",
				    p + 1);

			masklen = p ? mask : 32;
			af = AF_INET;
		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
			if (IN6_IS_ADDR_V4COMPAT(paddr))
				errx(EX_DATAERR,
				    "Use IPv4 instead of v4-compatible");
			if (p != NULL && mask > 128)
				errx(EX_DATAERR, "bad IPv6 mask width: %s",
				    p + 1);

			masklen = p ? mask : 128;
			af = AF_INET6;
		} else {
			/* Assume FQDN */
			if (lookup_host(arg, (struct in_addr *)paddr) != 0)
				errx(EX_NOHOST, "hostname ``%s'' unknown", arg);

			masklen = 32;
			type = IPFW_TABLE_ADDR;
			af = AF_INET;
		}
		break;
	case IPFW_TABLE_INTERFACE:
		/* Assume interface name. Copy significant data only */
		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
		memcpy(paddr, arg, mask);
		/* Set mask to exact match */
		masklen = 8 * IF_NAMESIZE;
		break;
	case IPFW_TABLE_NUMBER:
		/* Port or any other key */
		key = strtol(arg, &p, 10);
		if (*p != '\0')
			errx(EX_DATAERR, "Invalid number: %s", arg);

		pkey = (uint32_t *)paddr;
		*pkey = key;
		masklen = 32;
		break;
	case IPFW_TABLE_FLOW:
		/* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
		tfe = &tentry->k.flow;
		af = 0;

		/* Handle <ipv4|ipv6> */
		if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
			if ((p = strchr(arg, ',')) != NULL)
				*p++ = '\0';
			/* Determine family using temporary storage */
			if (inet_pton(AF_INET, arg, &tmp) == 1) {
				if (af != 0 && af != AF_INET)
					errx(EX_DATAERR,
					    "Inconsistent address family\n");
				af = AF_INET;
				memcpy(&tfe->a.a4.sip, &tmp, 4);
			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
				if (af != 0 && af != AF_INET6)
					errx(EX_DATAERR,
					    "Inconsistent address family\n");
				af = AF_INET6;
				memcpy(&tfe->a.a6.sip6, &tmp, 16);
			}

			arg = p;
		}

		/* Handle <proto-num|proto-name> */
		if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
			if (arg == NULL)
				errx(EX_DATAERR, "invalid key: proto missing");
			if ((p = strchr(arg, ',')) != NULL)
				*p++ = '\0';

			key = strtol(arg, &pp, 10);
			if (*pp != '\0') {
				if ((pent = getprotobyname(arg)) == NULL)
					errx(EX_DATAERR, "Unknown proto: %s",
					    arg);
				else
					key = pent->p_proto;
			}
			
			if (key > 255)
				errx(EX_DATAERR, "Bad protocol number: %u",key);

			tfe->proto = key;

			arg = p;
		}

		/* Handle <port-num|service-name> */
		if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
			if (arg == NULL)
				errx(EX_DATAERR, "invalid key: src port missing");
			if ((p = strchr(arg, ',')) != NULL)
				*p++ = '\0';

			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
				if ((sent = getservbyname(arg, NULL)) == NULL)
					errx(EX_DATAERR, "Unknown service: %s",
					    arg);
				else
					key = sent->s_port;
			}
			
			tfe->sport = port;

			arg = p;
		}

		/* Handle <ipv4|ipv6>*/
		if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
			if (arg == NULL)
				errx(EX_DATAERR, "invalid key: dst ip missing");
			if ((p = strchr(arg, ',')) != NULL)
				*p++ = '\0';
			/* Determine family using temporary storage */
			if (inet_pton(AF_INET, arg, &tmp) == 1) {
				if (af != 0 && af != AF_INET)
					errx(EX_DATAERR,
					    "Inconsistent address family");
				af = AF_INET;
				memcpy(&tfe->a.a4.dip, &tmp, 4);
			} else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
				if (af != 0 && af != AF_INET6)
					errx(EX_DATAERR,
					    "Inconsistent address family");
				af = AF_INET6;
				memcpy(&tfe->a.a6.dip6, &tmp, 16);
			}

			arg = p;
		}

		/* Handle <port-num|service-name> */
		if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
			if (arg == NULL)
				errx(EX_DATAERR, "invalid key: dst port missing");
			if ((p = strchr(arg, ',')) != NULL)
				*p++ = '\0';

			if ((port = htons(strtol(arg, NULL, 10))) == 0) {
				if ((sent = getservbyname(arg, NULL)) == NULL)
					errx(EX_DATAERR, "Unknown service: %s",
					    arg);
				else
					key = sent->s_port;
			}
			
			tfe->dport = port;

			arg = p;
		}

		tfe->af = af;

		break;
	
	default:
		errx(EX_DATAERR, "Unsupported table type: %d", type);
	}

	tentry->subtype = af;
	tentry->masklen = masklen;
}
Example #17
0
/* ARGSUSED */
char *
inet_ntop(int af, const void *addr, char *buf, int addrlen)
{
	static char local_buf[INET6_ADDRSTRLEN];
	static char *err_buf1 = "<badaddr>";
	static char *err_buf2 = "<badfamily>";
	in6_addr_t	*v6addr;
	uchar_t		*v4addr;
	char		*caddr;

	/*
	 * We don't allow thread unsafe inet_ntop calls, they
	 * must pass a non-null buffer pointer. For DEBUG mode
	 * we use the ASSERT() and for non-debug kernel it will
	 * silently allow it for now. Someday we should remove
	 * the static buffer from this function.
	 */

	ASSERT(buf != NULL);
	if (buf == NULL)
		buf = local_buf;
	buf[0] = '\0';

	/* Let user know politely not to send NULL or unaligned addr */
	if (addr == NULL || !(OK_32PTR(addr))) {
#ifdef DEBUG
		cmn_err(CE_WARN, "inet_ntop: addr is <null> or unaligned");
#endif
		return (err_buf1);
	}


#define	UC(b)	(((int)b) & 0xff)
	switch (af) {
	case AF_INET:
		ASSERT(addrlen >= INET_ADDRSTRLEN);
		v4addr = (uchar_t *)addr;
		(void) sprintf(buf, "%03d.%03d.%03d.%03d",
		    UC(v4addr[0]), UC(v4addr[1]), UC(v4addr[2]), UC(v4addr[3]));
		return (buf);

	case AF_INET6:
		ASSERT(addrlen >= INET6_ADDRSTRLEN);
		v6addr = (in6_addr_t *)addr;
		if (IN6_IS_ADDR_V4MAPPED(v6addr)) {
			caddr = (char *)addr;
			(void) sprintf(buf, "::ffff:%d.%d.%d.%d",
			    UC(caddr[12]), UC(caddr[13]),
			    UC(caddr[14]), UC(caddr[15]));
		} else if (IN6_IS_ADDR_V4COMPAT(v6addr)) {
			caddr = (char *)addr;
			(void) sprintf(buf, "::%d.%d.%d.%d",
			    UC(caddr[12]), UC(caddr[13]), UC(caddr[14]),
			    UC(caddr[15]));
		} else if (IN6_IS_ADDR_UNSPECIFIED(v6addr)) {
			(void) sprintf(buf, "::");
		} else {
			convert2ascii(buf, v6addr);
		}
		return (buf);

	default:
		return (err_buf2);
	}
#undef UC
}
Example #18
0
struct hostent *
getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
	struct hostent *he1, *he2;
	struct net_data *net_data = init();

	/* Sanity Checks. */
	if (src == NULL) {
		*error_num = NO_RECOVERY;
		return (NULL);
	}
		
	switch (af) {
	case AF_INET:
		if (len != (size_t)INADDRSZ) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		break;
	case AF_INET6:
		if (len != (size_t)IN6ADDRSZ) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		break;
	default:
		*error_num = NO_RECOVERY;
		return (NULL);
	}

	/*
	 * Lookup IPv4 and IPv4 mapped/compatible addresses
	 */
	if ((af == AF_INET6 &&
	     IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)src)) ||
	    (af == AF_INET6 &&
	     IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)src)) ||
	    (af == AF_INET)) {
		const char *cp = src;

		if (af == AF_INET6)
			cp += 12;
		he1 = gethostbyaddr_p(cp, 4, AF_INET, net_data);
		if (he1 == NULL) {
			*error_num = net_data->res->res_h_errno;
			return (NULL);
		}
		he2 = copyandmerge(he1, NULL, af, error_num);
		if (he2 == NULL)
			return (NULL);
		/*
		 * Restore original address if mapped/compatible.
		 */
		if (af == AF_INET6)
			memcpy(he1->h_addr, src, len);
		return (he2);
	}

	/*
	 * Lookup IPv6 address.
	 */
	if (memcmp((const struct in6_addr *)src, &in6addr_any, 16) == 0) {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}

	he1 = gethostbyaddr_p(src, 16, AF_INET6, net_data);
	if (he1 == NULL) {
		*error_num = net_data->res->res_h_errno;
		return (NULL);
	}
	return (copyandmerge(he1, NULL, af, error_num));
}
Example #19
0
struct hostent * W32_CALL
getipnodebyaddr (const void *src, size_t len, int af, int *error)
{
  struct hostent *he1, *he2;
  const  BYTE *cp = (const BYTE*) src;

  SOCK_DEBUGF (("\ngetipnodebyaddr: "));

  if (!src)
  {
    *error = NO_RECOVERY;
    return (NULL);
  }

  switch (af)
  {
    case AF_INET:
         if (len < INADDRSZ)
         {
           *error = NO_RECOVERY;
           return (NULL);
         }
         break;
#if defined(USE_IPV6)
    case AF_INET6:
         if (len < IN6ADDRSZ)
         {
           *error = NO_RECOVERY;
           return (NULL);
         }
         break;
#endif
    default:
         *error = NO_RECOVERY;
         return (NULL);
  }

  /* Look up IPv4 and IPv4 mapped/compatible addresses.
   */
  if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(cp)) ||
      (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(cp)) ||
      (af == AF_INET))
  {
    if (af == AF_INET6)
       cp += 12;

    SOCK_ENTER_SCOPE();
    he1 = gethostbyaddr ((const char*)cp, 4, AF_INET);
    SOCK_LEAVE_SCOPE();

    if (af == AF_INET)
       goto ret_copy;

    /* Convert from AF_INET to AF_INET6.
     */
    he2 = copyandmerge (he1, NULL, af, error);
    if (he2)
    {
      memcpy (he2->h_addr, src, len);  /* Restore original address */
      SOCK_DEBUGF (("%s", af == AF_INET ?
                    inet_ntoa(*(struct in_addr*)&he2->h_addr) :
                    _inet6_ntoa(he2->h_addr)));
    }
    return (he2);
  }

  he1 = gethostbyaddr (src, len, AF_INET6);   /* Lookup IPv6 address */

ret_copy:
  if (!he1)
  {
    *error = HOST_NOT_FOUND;
    return (NULL);
  }
  return copyandmerge (he1, NULL, af, error);
}
Example #20
0
/*
 * getnameinfo
 *
 * We handle some "trival" cases locally.  If the caller passes
 * NI_NUMERICHOST (only), then this call turns into a getservbyport
 * to get the service name + inet_pton() to create a host string.
 * If the caller passes NI_NUMERICSERV (only), then we zero out the port
 * number, complete the getnameinfo, and use printf() to create a service
 * string.  If the caller specifies both NI_NUMERICHOST and NI_NUMERICSERV,
 * we inet_ntop() and printf() and return the results.
 */
si_item_t *
si_nameinfo(si_mod_t *si, const struct sockaddr *sa, int flags, const char *interface, uint32_t *err)
{
	si_item_t *out = NULL;
	const struct sockaddr *lookup_sa;
	struct sockaddr_in s4;
	struct in_addr a4;
	struct in6_addr a6;
	const uint32_t unused = 0;
	void *addr = NULL;
	char *host = NULL;
	char *serv = NULL;
	uint32_t ifnum = 0;
	uint16_t port = 0;

	int do_host_lookup = ((flags & NI_NUMERICHOST) == 0);
	int do_serv_lookup = ((flags & NI_NUMERICSERV) == 0);

	/* check input */
	if ((si == NULL) || (sa == NULL))
	{
		if (err != NULL) *err = SI_STATUS_EAI_FAIL;
		return NULL;
	}

	if (err != NULL) *err = SI_STATUS_NO_ERROR;

	lookup_sa = sa;

	if (sa->sa_family == AF_INET)
	{
		struct sockaddr_in *s4 = (struct sockaddr_in *)sa;
		memcpy(&a4, &s4->sin_addr, sizeof(a4));
		port = s4->sin_port;
		addr = &a4;
	}
	else if (sa->sa_family == AF_INET6)
	{
		struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa;
		memcpy(&a6, &s6->sin6_addr, sizeof(a6));
		port = s6->sin6_port;

		/* Look for scope id in IPv6 Link Local, Multicast Node Local, and Multicast Link Local */
		if (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&s6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))
		{
			ifnum = ntohs(a6.__u6_addr.__u6_addr16[1]);
			if (ifnum == 0)
			{
				ifnum = s6->sin6_scope_id;
				a6.__u6_addr.__u6_addr16[1] = htons(ifnum);
			}

			if ((ifnum != s6->sin6_scope_id) && (s6->sin6_scope_id != 0))
			{
				if (err != NULL) *err = SI_STATUS_EAI_FAIL;
				return NULL;
			}
		}

		/* v4 mapped and compat addresses are converted to plain v4 */
		if (IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&s6->sin6_addr))
		{
			memcpy(&a4, &s6->sin6_addr.s6_addr[12], sizeof(a4));
			addr = &a4;
			memset(&s4, 0, sizeof(s4));
			s4.sin_len = sizeof(s4);
			s4.sin_family = AF_INET;
			s4.sin_port = port;
			memcpy(&s4.sin_addr, &a4, sizeof(s4.sin_addr));
			lookup_sa = (const struct sockaddr *)&s4;
		}
		else
		{
			addr = &a6;
		}
	}
	else
	{
		if (err != NULL) *err = SI_STATUS_EAI_FAMILY;
		return NULL;
	}

	if (do_host_lookup == 1)
	{
		si_item_t *item = si_host_byaddr(si, addr, lookup_sa->sa_family, interface, NULL);
		if (item != NULL)
		{
			struct hostent *h;
			h = (struct hostent *)((uintptr_t)item + sizeof(si_item_t));
			host = strdup(h->h_name);
			si_item_release(item);
			if (host == NULL)
			{
				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
				return NULL;
			}
		}
	}

	if ((do_serv_lookup == 1) && (port != 0))
	{
		si_item_t *item = si_service_byport(si, port, NULL);
		if (item != NULL)
		{
			struct servent *s;
			s = (struct servent *)((uintptr_t)item + sizeof(si_item_t));
			serv = strdup(s->s_name);
			si_item_release(item);
			if (serv == NULL)
			{
				free(host);
				if (err != NULL) *err = SI_STATUS_EAI_MEMORY;
				return NULL;
			}
		}
	}

	/*
	 * Return numeric host name for NI_NUMERICHOST or if lookup failed, but not
	 * if NI_NAMEREQD is specified (so that we later fail with EAI_NONAME).
	 */
	if ((host == NULL) && ((flags & NI_NAMEREQD) == 0))
	{
		char tmp[INET6_ADDRSTRLEN + 1 + IF_NAMESIZE + 1];
		tmp[0] = '\0';
		if (sa->sa_family == AF_INET)
		{
			char buf[INET_ADDRSTRLEN];
			if (inet_ntop(AF_INET, &a4, buf, sizeof(buf)) != 0)
			{
				host = strdup(buf);
			}
		}
		else if (sa->sa_family == AF_INET6)
		{
			char buf[INET6_ADDRSTRLEN];

			/* zero the embedded scope ID */
			if (ifnum != 0)
			{
				a6.__u6_addr.__u6_addr16[1] = 0;
			}

			if (inet_ntop(AF_INET6, &a6, buf, sizeof(buf)) != 0)
			{
				if (ifnum != 0)
				{
					char ifname[IF_NAMESIZE];
					if (if_indextoname(ifnum, ifname) != NULL)
					{
						asprintf(&host, "%s%%%s", buf, ifname);
					}
					else
					{
						/* ENXIO */
						if (err != NULL) *err = SI_STATUS_EAI_FAIL;
						return NULL;
					}
				}
				else
				{
					host = strdup(buf);
				}
			}
		}
	}

	/* Return numeric service name for NI_NUMERICSERV or if lookup failed. */
	if (serv == NULL)
	{
		asprintf(&serv, "%hu", ntohs(port));
	}

	if ((host == NULL) || (serv == NULL))
	{
		if (err != NULL)
		{
			if ((flags & NI_NAMEREQD) != 0)
			{
				*err = SI_STATUS_EAI_NONAME;
			}
			else
			{
				*err = SI_STATUS_EAI_MEMORY;
			}
		}
	}
	else
	{
		out = (si_item_t *)LI_ils_create("L4444ss", (unsigned long)si, CATEGORY_NAMEINFO, 1, unused, unused, host, serv);
	}

	free(host);
	free(serv);
	return out;
}
void cXVDRServer::NewClientConnected(int fd)
{
  struct sockaddr_storage sin;
  socklen_t len = sizeof(sin);
  in_addr_t *ipv4_addr = NULL;

  if (getpeername(fd, (struct sockaddr *)&sin, &len))
  {
    ERRORLOG("getpeername() failed, dropping new incoming connection %d", m_IdCnt);
    close(fd);
    return;
  }

  if (!m_IPv4Fallback)
  {
    if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&sin)->sin6_addr) ||
        IN6_IS_ADDR_V4COMPAT(&((struct sockaddr_in6 *)&sin)->sin6_addr))
      ipv4_addr = &((struct sockaddr_in6 *)&sin)->sin6_addr.s6_addr32[3];
  }
  else
    ipv4_addr = &((struct sockaddr_in *)&sin)->sin_addr.s_addr;

  // Acceptable() method only supports in_addr_t argument so we're currently checking IPv4 hosts only
  if (ipv4_addr)
  {
    cAllowedHosts AllowedHosts(m_AllowedHostsFile);
    if (!AllowedHosts.Acceptable(*ipv4_addr))
    {
      ERRORLOG("Address not allowed to connect (%s)", *m_AllowedHostsFile);
      close(fd);
      return;
    }
  }

  if (fcntl(fd, F_SETFL, fcntl (fd, F_GETFL) | O_NONBLOCK) == -1)
  {
    ERRORLOG("Error setting control socket to nonblocking mode");
    close(fd);
    return;
  }

  int val = 1;
  setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));

#ifndef __FreeBSD__
  val = 30;
  setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &val, sizeof(val));

  val = 15;
  setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &val, sizeof(val));

  val = 5;
  setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &val, sizeof(val));
#endif

  val = 1;
  setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));

  if (!m_IPv4Fallback)
    INFOLOG("Client %s:%i with ID %d connected.", xvdr_inet_ntoa(((struct sockaddr_in6 *)&sin)->sin6_addr), ((struct sockaddr_in6 *)&sin)->sin6_port, m_IdCnt);
  else
    INFOLOG("Client %s:%i with ID %d connected.", inet_ntoa(((struct sockaddr_in *)&sin)->sin_addr), ((struct sockaddr_in *)&sin)->sin_port, m_IdCnt);
  cXVDRClient *connection = new cXVDRClient(fd, m_IdCnt);
  m_clients.push_back(connection);
  m_IdCnt++;
}
Example #22
0
/*
 * Type0 routing header processing
 *
 * RFC2292 backward compatibility warning: no support for strict/loose bitmap,
 * as it was dropped between RFC1883 and RFC2460.
 */
static int
ip6_rthdr0(struct mbuf *m, struct ip6_hdr *ip6, 
	struct ip6_rthdr0 *rh0)
{
	int addrs, index;
	struct in6_addr *nextaddr, tmpaddr;
	const struct ip6aux *ip6a;

	if (rh0->ip6r0_segleft == 0)
		return (0);

	if (rh0->ip6r0_len % 2
#ifdef COMPAT_RFC1883
	    || rh0->ip6r0_len > 46
#endif
		) {
		/*
		 * Type 0 routing header can't contain more than 23 addresses.
		 * RFC 2462: this limitation was removed since strict/loose
		 * bitmap field was deleted.
		 */
		IP6_STATINC(IP6_STAT_BADOPTIONS);
		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
			    (char *)&rh0->ip6r0_len - (char *)ip6);
		return (-1);
	}

	if ((addrs = rh0->ip6r0_len / 2) < rh0->ip6r0_segleft) {
		IP6_STATINC(IP6_STAT_BADOPTIONS);
		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
			    (char *)&rh0->ip6r0_segleft - (char *)ip6);
		return (-1);
	}

	index = addrs - rh0->ip6r0_segleft;
	rh0->ip6r0_segleft--;
	nextaddr = ((struct in6_addr *)(rh0 + 1)) + index;

	/*
	 * reject invalid addresses.  be proactive about malicious use of
	 * IPv4 mapped/compat address.
	 * XXX need more checks?
	 */
	if (IN6_IS_ADDR_MULTICAST(nextaddr) ||
	    IN6_IS_ADDR_UNSPECIFIED(nextaddr) ||
	    IN6_IS_ADDR_V4MAPPED(nextaddr) ||
	    IN6_IS_ADDR_V4COMPAT(nextaddr)) {
		p6stat[IP6_STAT_BADOPTIONS]++;
		goto bad;
	}
	if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
	    IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst) ||
	    IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst) ||
	    IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
		IP6_STATINC(IP6_STAT_BADOPTIONS);
		goto bad;
	}

	/*
	 * Determine the scope zone of the next hop, based on the interface
	 * of the current hop. [RFC4007, Section 9]
	 * Then disambiguate the scope zone for the next hop (if necessary). 
	 */
	if ((ip6a = ip6_getdstifaddr(m)) == NULL)
		goto bad;
	if (in6_setzoneid(nextaddr, ip6a->ip6a_scope_id) != 0) {
		IP6_STATINC(IP6_STAT_BADSCOPE);
		goto bad;
	}

	/*
	 * Swap the IPv6 destination address and nextaddr. Forward the packet.
	 */
	tmpaddr = *nextaddr;
	*nextaddr = ip6->ip6_dst;
	in6_clearscope(nextaddr); /* XXX */
	ip6->ip6_dst = tmpaddr;

#ifdef COMPAT_RFC1883
	if (rh0->ip6r0_slmap[index / 8] & (1 << (7 - (index % 8))))
		ip6_forward(m, IPV6_SRCRT_NEIGHBOR);
	else
		ip6_forward(m, IPV6_SRCRT_NOTNEIGHBOR);
#else
	ip6_forward(m, 1);
#endif

	return (-1);			/* m would be freed in ip6_forward() */

  bad:
	m_freem(m);
	return (-1);
}
static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
	struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv;
	struct net_device_stats *stats = &tunnel->stat;
	struct iphdr  *tiph = &tunnel->parms.iph;
	u8     tos = tunnel->parms.iph.tos;
	u16    df = tiph->frag_off;
	struct rtable *rt;     			/* Route to the other host */
	struct net_device *tdev;			/* Device to other host */
	struct iphdr  *old_iph = skb->nh.iph;
#ifdef CONFIG_NET_IPIP_IPV6
	struct ipv6hdr *iph6 = skb->nh.ipv6h;
#endif
	struct iphdr  *iph;			/* Our new IP header */
	int    max_headroom;			/* The extra header space needed */
	u32    dst = tiph->daddr;
	int    mtu;
	u8 protocol = 0; 

	switch (skb->protocol) {
	case __constant_htons(ETH_P_IP):
		protocol = IPPROTO_IPIP;
		break;
#ifdef CONFIG_NET_IPIP_IPV6
	case __constant_htons(ETH_P_IPV6):
		protocol = IPPROTO_IPV6;
		break;
#endif
	}

	if (tunnel->recursion++) {
		tunnel->stat.collisions++;
		goto tx_error;
	}

	switch(skb->protocol) {
	case __constant_htons(ETH_P_IP):
		if (tunnel->parms.iph.protocol &&
		    tunnel->parms.iph.protocol != IPPROTO_IPIP)
			goto tx_error;
		if (tos&1)
			tos = old_iph->tos;
		break;
#ifdef CONFIG_NET_IPIP_IPV6
	case __constant_htons(ETH_P_IPV6):
		if (tunnel->parms.iph.protocol &&
		    tunnel->parms.iph.protocol != IPPROTO_IPV6)
			goto tx_error;
		break;
#endif
	default:
		goto tx_error;
	}

	if (!dst) {
		switch(skb->protocol){
		case __constant_htons(ETH_P_IP):
			/* NBMA tunnel */
			if ((rt = (struct rtable*)skb->dst) == NULL) {
				tunnel->stat.tx_fifo_errors++;
				goto tx_error;
			}
			dst = rt->rt_gateway;
			break;
#ifdef CONFIG_NET_IPIP_IPV6
		case __constant_htons(ETH_P_IPV6):
		    {
			struct in6_addr *addr6 = &iph6->daddr;
			if (addr6->s6_addr16[0] == htons(0x2002)) {
				memcpy(&dst, &addr6->s6_addr16[1], 4);
			} else {
				/* dst is zero */
				struct neighbour *neigh = NULL;
				if (skb->dst)
					neigh = skb->dst->neighbour;
				if (neigh == NULL) {
					printk(KERN_DEBUG "tunl: nexthop == NULL\n");
					goto tx_error;
				}
				addr6 = (struct in6_addr*)&neigh->primary_key;
				if (IN6_IS_ADDR_UNSPECIFIED(addr6))
					addr6 = &skb->nh.ipv6h->daddr;
				if (IN6_IS_ADDR_V4COMPAT(addr6))
					dst = addr6->s6_addr32[3];
#ifdef CONFIG_IPV6_6TO4_NEXTHOP
				else if (addr6->s6_addr16[0] == htons(0x2002)) 
					memcpy(&dst, &addr6->s6_addr16[1], 4);
#endif
				else
					goto tx_error_icmp;
			}
			break;
		    }
#endif
		}
		if (!dst)
			goto tx_error_icmp;
	}

	if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
		tunnel->stat.tx_carrier_errors++;
		goto tx_error_icmp;
	}
	tdev = rt->u.dst.dev;

	if (tdev == dev) {
		ip_rt_put(rt);
		tunnel->stat.collisions++;
		goto tx_error;
	}

	if (tiph->frag_off)
		mtu = rt->u.dst.pmtu - sizeof(struct iphdr);
	else
		mtu = skb->dst ? skb->dst->pmtu : dev->mtu;

	if (mtu < 68) {
		tunnel->stat.collisions++;
		ip_rt_put(rt);
		goto tx_error;
	}

	switch(skb->protocol){
	case __constant_htons(ETH_P_IP):
		if (skb->dst && mtu < skb->dst->pmtu)
			skb->dst->pmtu = mtu;

		df |= (old_iph->frag_off&htons(IP_DF));

		if ((old_iph->frag_off&htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) {
			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
			ip_rt_put(rt);
			goto tx_error;
		}
		break;

#ifdef CONFIG_NET_IPIP_IPV6
	case __constant_htons(ETH_P_IPV6):
#if 0
		if (mtu < IPV6_MIN_MTU) {
			/* XXX: too small; we should fragment this packet? */
			tunnel->stat.tx_carrier_errors++;
			goto tx_error_icmp;
		}
#endif
		if (skb->len > mtu && mtu > IPV6_MIN_MTU) {
			icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
			ip_rt_put(rt);
			goto tx_error;
		}
		df = mtu > IPV6_MIN_MTU ? htons(IP_DF) : 0;
		break;
#endif
	}
	if (tunnel->err_count > 0) {
		if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
			tunnel->err_count--;
			dst_link_failure(skb);
		} else
			tunnel->err_count = 0;
	}

	/*
	 * Okay, now see if we can stuff it in the buffer as-is.
	 */
	max_headroom = (((tdev->hard_header_len+15)&~15)+sizeof(struct iphdr));
	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
		if (!new_skb) {
			ip_rt_put(rt);
  			stats->tx_dropped++;
			dev_kfree_skb(skb);
			tunnel->recursion--;
			return 0;
		}
		if (skb->sk)
			skb_set_owner_w(new_skb, skb->sk);
		dev_kfree_skb(skb);
		skb = new_skb;
		old_iph = skb->nh.iph;
	}

	skb->h.raw = skb->nh.raw;
	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
	dst_release(skb->dst);
	skb->dst = &rt->u.dst;

	/*
	 *	Push down and install the IPIP header.
	 */

	iph 			=	skb->nh.iph;
	iph->version		=	4;
	iph->ihl		=	sizeof(struct iphdr)>>2;
	iph->daddr		=	rt->rt_dst;
	iph->saddr		=	rt->rt_src;

	iph->ttl		=	tiph->ttl;
	iph->frag_off		=	df;

	switch(skb->protocol){
	case __constant_htons(ETH_P_IP):
		iph->protocol	=	protocol;
		iph->tos	=	INET_ECN_encapsulate(tos, old_iph->tos);
		if (iph->ttl == 0)
			iph->ttl =	old_iph->ttl;
		break;
#ifdef CONFIG_NET_IPIP_IPV6
	case __constant_htons(ETH_P_IPV6):
		iph->protocol	=	protocol;
		iph->tos	=	INET_ECN_encapsulate(tos, ip6_get_dsfield(iph6));
		if (iph->ttl == 0)
			iph->ttl =	iph6->hop_limit;
		break;
#endif
	}

	nf_reset(skb);

	IPTUNNEL_XMIT();
	tunnel->recursion--;
	return 0;

tx_error_icmp:
	dst_link_failure(skb);
tx_error:
	stats->tx_errors++;
	dev_kfree_skb(skb);
	tunnel->recursion--;
	return 0;
}
Example #24
0
static int lc_local_addresses(lua_State *L)
{
#ifndef _WIN32
	/* Link-local IPv4 addresses; see RFC 3927 and RFC 5735 */
	const long ip4_linklocal = htonl(0xa9fe0000); /* 169.254.0.0 */
	const long ip4_mask      = htonl(0xffff0000);
	struct ifaddrs *addr = NULL, *a;
#endif
	int n = 1;
	int type = luaL_checkoption(L, 1, "both", type_strings);
	const char link_local = lua_toboolean(L, 2); /* defaults to 0 (false) */
	const char ipv4 = (type == 0 || type == 1);
	const char ipv6 = (type == 0 || type == 2);

#ifndef _WIN32
	if (getifaddrs(&addr) < 0) {
		lua_pushnil(L);
		lua_pushfstring(L, "getifaddrs failed (%d): %s", errno,
		strerror(errno));
		return 2;
	}
#endif
	lua_newtable(L);

#ifndef _WIN32
	for (a = addr; a; a = a->ifa_next) {
		int family;
		char ipaddr[INET6_ADDRSTRLEN];
		const char *tmp = NULL;

		if (a->ifa_addr == NULL || a->ifa_flags & IFF_LOOPBACK)
			continue;

		family = a->ifa_addr->sa_family;

		if (ipv4 && family == AF_INET) {
			struct sockaddr_in *sa = (struct sockaddr_in *)a->ifa_addr;
			if (!link_local &&((sa->sin_addr.s_addr & ip4_mask) == ip4_linklocal))
				continue;
			tmp = inet_ntop(family, &sa->sin_addr, ipaddr, sizeof(ipaddr));
		} else if (ipv6 && family == AF_INET6) {
			struct sockaddr_in6 *sa = (struct sockaddr_in6 *)a->ifa_addr;
			if (!link_local && IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr))
				continue;
			if (IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr) || IN6_IS_ADDR_V4COMPAT(&sa->sin6_addr))
				continue;
			tmp = inet_ntop(family, &sa->sin6_addr, ipaddr, sizeof(ipaddr));
		}

		if (tmp != NULL) {
			lua_pushstring(L, tmp);
			lua_rawseti(L, -2, n++);
		}
		/* TODO: Error reporting? */
	}

	freeifaddrs(addr);
#else
	if (ipv4) {
		lua_pushstring(L, "0.0.0.0");
		lua_rawseti(L, -2, n++);
	}
	if (ipv6) {
		lua_pushstring(L, "::");
		lua_rawseti(L, -2, n++);
	}
#endif
	return 1;
}
Example #25
0
struct hostent *
getipnodebyaddr(const void *src, size_t len, int af, int *errp)
{
	struct hostent *hp;
	int rval;
#ifdef INET6
	struct in6_addr addrbuf;
#else
	struct in_addr addrbuf;
#endif

	static const ns_dtab dtab[] = {
		NS_FILES_CB(_files_ghbyaddr, NULL)
		{ NSSRC_DNS, _dns_ghbyaddr, NULL },
		NS_NIS_CB(_nis_ghbyaddr, NULL)
#ifdef ICMPNL
		{ NSSRC_ICMP, _icmp_ghbyaddr, NULL },
#endif
		{ 0 }
	};

	*errp = HOST_NOT_FOUND;

	switch (af) {
	case AF_INET:
		if (len != sizeof(struct in_addr)) {
			*errp = NO_RECOVERY;
			return NULL;
		}
		if ((long)src & ~(sizeof(struct in_addr) - 1)) {
			memcpy(&addrbuf, src, len);
			src = &addrbuf;
		}
		if (((struct in_addr *)src)->s_addr == 0)
			return NULL;
		break;
#ifdef INET6
	case AF_INET6:
		if (len != sizeof(struct in6_addr)) {
			*errp = NO_RECOVERY;
			return NULL;
		}
		if ((long)src & ~(sizeof(struct in6_addr) / 2 - 1)) {	/*XXX*/
			memcpy(&addrbuf, src, len);
			src = &addrbuf;
		}
		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
			return NULL;
		if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
		||  IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
			src = (char *)src +
			    (sizeof(struct in6_addr) - sizeof(struct in_addr));
			af = AF_INET;
			len = sizeof(struct in_addr);
		}
		break;
#endif
	default:
		*errp = NO_RECOVERY;
		return NULL;
	}

	rval = nsdispatch(&hp, dtab, NSDB_HOSTS, "ghbyaddr", default_src,
			  src, len, af, errp);
	return (rval == NS_SUCCESS) ? hp : NULL;
}
Example #26
0
static void 
accept_connection(int pfd, void *data)
{
  static time_t      last_oper_notice = 0;

  struct irc_sockaddr sai;
  struct irc_inaddr addr;
  int                fd;
  int pe;
  struct Listener *  listener = data;

  assert(listener != NULL);
  if(listener == NULL)
    return;
  /*
   * There may be many reasons for error return, but
   * in otherwise correctly working environment the
   * probable cause is running out of file descriptors
   * (EMFILE, ENFILE or others?). The man pages for
   * accept don't seem to list these as possible,
   * although it's obvious that it may happen here.
   * Thus no specific errors are tested at this
   * point, just assume that connections cannot
   * be accepted until some old is closed first.
   */

  fd = comm_accept(listener->fd, &sai);

  copy_s_addr(IN_ADDR(addr), S_ADDR(sai));

#ifdef IPV6
  if((IN6_IS_ADDR_V4MAPPED(&IN_ADDR2(addr))) ||
  	(IN6_IS_ADDR_V4COMPAT(&IN_ADDR2(addr))))
  {
    memmove(&addr.sins.sin.s_addr, addr.sins.sin6.s6_addr+12,
            sizeof(struct in_addr));

    sai.sins.sin.sin_family = AF_INET;
  }
#endif

  if (fd < 0)
    {
      /* Re-register a new IO request for the next accept .. */
      comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
                     accept_connection, listener, 0);
      return;
    }
  /*
   * check for connection limit
   */
  if ((MAXCONNECTIONS - 10) < fd)
    {
      ++ServerStats->is_ref;
      /*
       * slow down the whining to opers bit
       */
      if((last_oper_notice + 20) <= CurrentTime)
	{
	  sendto_realops_flags(UMODE_ALL, L_ALL,"All connections in use. (%s)",
			       get_listener_name(listener));
	  last_oper_notice = CurrentTime;
	}

      send(fd, "ERROR :All connections in use\r\n", 32, 0);
      fd_close(fd);
      /* Re-register a new IO request for the next accept .. */
      comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
                     accept_connection, listener, 0);
      return;
    }

  /* Do an initial check we aren't connecting too fast or with too many
   * from this IP... */
  if ((pe = conf_connect_allowed(&addr, sai.sins.sin.sin_family)) != 0)
  {
    ServerStats->is_ref++;

    /* XXX - this can only be BANNED_CLIENT? */
    switch (pe)
    {
      case BANNED_CLIENT:
        send(fd, DLINE_WARNING, sizeof(DLINE_WARNING)-1, 0);
        break;
    }

    fd_close(fd);

    /* Re-register a new IO request for the next accept .. */
    comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
                   accept_connection, listener, 0);
    return;
  }

  ServerStats->is_ac++;

  add_connection(listener, fd);

  /* Re-register a new IO request for the next accept .. */
  comm_setselect(listener->fd, FDLIST_SERVICE, COMM_SELECT_READ,
    accept_connection, listener, 0);
}
Example #27
0
/*% performs a reverse lookup of address src which is len bytes long. af denotes the protocol family, typically #PF_INET or PF_INET6. */
struct hostent *
lwres_getipnodebyaddr(const void *src, size_t len, int af, int *error_num) {
	struct hostent *he1, *he2;
	lwres_context_t *lwrctx = NULL;
	lwres_gnbaresponse_t *by = NULL;
	lwres_result_t n;
	union {
		const void *konst;
		struct in6_addr *in6;
	} u;

	/*
	 * Sanity checks.
	 */
	if (src == NULL) {
		*error_num = NO_RECOVERY;
		return (NULL);
	}

	switch (af) {
	case AF_INET:
		if (len != (unsigned int)INADDRSZ) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		break;
	case AF_INET6:
		if (len != (unsigned int)IN6ADDRSZ) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		break;
	default:
		*error_num = NO_RECOVERY;
		return (NULL);
	}

	/*
	 * The de-"const"-ing game is done because at least one
	 * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
	 * macros in such a way that they discard the const with
	 * internal casting, and gcc ends up complaining.  Rather
	 * than replacing their own (possibly optimized) definitions
	 * with our own, cleanly discarding the const is the easiest
	 * thing to do.
	 */
	u.konst = src;

	/*
	 * Look up IPv4 and IPv4 mapped/compatible addresses.
	 */
	if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(u.in6)) ||
	    (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(u.in6)) ||
	    (af == AF_INET)) {
		const unsigned char *cp = src;

		if (af == AF_INET6)
			cp += 12;
		n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
		if (n == LWRES_R_SUCCESS)
			(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
		if (n == LWRES_R_SUCCESS)
			n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V4,
						INADDRSZ, cp, &by);
		if (n != LWRES_R_SUCCESS) {
			lwres_conf_clear(lwrctx);
			lwres_context_destroy(&lwrctx);
			if (n == LWRES_R_NOTFOUND)
				*error_num = HOST_NOT_FOUND;
			else
				*error_num = NO_RECOVERY;
			return (NULL);
		}
		he1 = hostfromaddr(by, AF_INET, cp);
		lwres_gnbaresponse_free(lwrctx, &by);
		lwres_conf_clear(lwrctx);
		lwres_context_destroy(&lwrctx);
		if (af != AF_INET6)
			return (he1);

		/*
		 * Convert from AF_INET to AF_INET6.
		 */
		he2 = copyandmerge(he1, NULL, af, error_num);
		lwres_freehostent(he1);
		if (he2 == NULL)
			return (NULL);
		/*
		 * Restore original address.
		 */
		memcpy(he2->h_addr, src, len);
		return (he2);
	}

	/*
	 * Lookup IPv6 address.
	 */
	if (memcmp(src, &in6addr_any, IN6ADDRSZ) == 0) {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}

	n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
	if (n == LWRES_R_SUCCESS)
		(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);
	if (n == LWRES_R_SUCCESS)
		n = lwres_getnamebyaddr(lwrctx, LWRES_ADDRTYPE_V6, IN6ADDRSZ,
					src, &by);
	if (n != 0) {
		lwres_conf_clear(lwrctx);
		lwres_context_destroy(&lwrctx);

		if (n == LWRES_R_NOTFOUND)
		       *error_num = HOST_NOT_FOUND;
		else
		       *error_num = NO_RECOVERY;

		return (NULL);
	}

	he1 = hostfromaddr(by, AF_INET6, src);
	lwres_gnbaresponse_free(lwrctx, &by);
	if (he1 == NULL)
		*error_num = NO_RECOVERY;
	lwres_conf_clear(lwrctx);
	lwres_context_destroy(&lwrctx);
	return (he1);
}
Example #28
0
/*
 * This is the IPv6 interface for "gethostbyaddr".
 */
struct hostent *
getipnodebyaddr(const void *src, size_t len, int type, int *error_num)
{
	struct in6_addr *addr6 = 0;
	struct in_addr *addr4 = 0;
	nss_XbyY_buf_t *buf = 0;
	nss_XbyY_buf_t *res = 0;
	struct netconfig *nconf;
	struct hostent *hp = 0;
	struct	nss_netdirbyaddr_in nssin;
	union	nss_netdirbyaddr_out nssout;
	int neterr;
	char tmpbuf[64];

	if (type == AF_INET6) {
		if ((addr6 = (struct in6_addr *)src) == NULL) {
			*error_num = HOST_NOT_FOUND;
			return (NULL);
		}
	} else if (type == AF_INET) {
		if ((addr4 = (struct in_addr *)src) == NULL) {
			*error_num = HOST_NOT_FOUND;
			return (NULL);
		}
	} else {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}
	/*
	 * Specific case: query for "::"
	 */
	if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}
	/*
	 * Step 1: IPv4-mapped address  or IPv4 Compat
	 */
	if ((type == AF_INET6 && len == 16) &&
	    ((IN6_IS_ADDR_V4MAPPED(addr6)) ||
	    (IN6_IS_ADDR_V4COMPAT(addr6)))) {
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			__IPv6_cleanup(buf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
			(void) memcpy(tmpbuf, addr6, sizeof (*addr6));
			tmpbuf[10] = 0xffU;
			tmpbuf[11] = 0xffU;
			nssin.arg.nss.host.addr = (const char *)tmpbuf;
		} else {
			nssin.arg.nss.host.addr = (const char *)addr6;
		}
		nssin.arg.nss.host.len = sizeof (struct in6_addr);
		nssin.arg.nss.host.type = AF_INET6;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			/* Failover case, try hosts db for v4 address */
			if (!gethostbyaddr_r(((char *)addr6) + 12,
			    sizeof (in_addr_t), AF_INET, buf->result,
			    buf->buffer, buf->buflen, error_num)) {
				__IPv6_cleanup(buf);
				return (NULL);
			}
			/* Found one, now format it into mapped/compat addr */
			if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
				__IPv6_cleanup(buf);
				*error_num = NO_RECOVERY;
				return (NULL);
			}
			/* Convert IPv4 to mapped/compat address w/name */
			hp = res->result;
			(void) __mapv4tov6(buf->result, 0, res,
			    IN6_IS_ADDR_V4MAPPED(addr6));
			__IPv6_cleanup(buf);
			free(res);
			return (hp);
		}
		/*
		 * At this point, we'll have a v4mapped hostent. If that's
		 * what was passed in, just return. If the request was a compat,
		 * twiggle the two bytes to make the mapped address a compat.
		 */
		hp = buf->result;
		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
			/* LINTED pointer cast */
			addr6 = (struct in6_addr *)hp->h_addr_list[0];
			addr6->s6_addr[10] = 0;
			addr6->s6_addr[11] = 0;
		}
		free(buf);
		return (hp);
	}
	/*
	 * Step 2: AF_INET, v4 lookup. Since we're going to search the
	 * ipnodes (v6) path first, we need to treat this as a v4mapped
	 * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The
	 * switch backend knows to lookup v4's (not v4mapped) from the
	 * name services.
	 */
	if (type == AF_INET) {
		struct in6_addr v4mapbuf;
		addr6 = &v4mapbuf;

		IN6_INADDR_TO_V4MAPPED(addr4, addr6);
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			freenetconfigent(nconf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		nssin.arg.nss.host.addr = (const char *)addr6;
		nssin.arg.nss.host.len = sizeof (struct in6_addr);
		nssin.arg.nss.host.type = AF_INET6;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			/* Failover case, try hosts db for v4 address */
			hp = buf->result;
			if (!gethostbyaddr_r(src, len, type, buf->result,
			    buf->buffer, buf->buflen, error_num)) {
				__IPv6_cleanup(buf);
				return (NULL);
			}
			free(buf);
			return (hp);
		}
		if ((hp = __mappedtov4(buf->result, error_num)) == NULL) {
			__IPv6_cleanup(buf);
			return (NULL);
		}
		__IPv6_cleanup(buf);
		return (hp);
	}
	/*
	 * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call.
	 */
	if (type == AF_INET6) {
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			freenetconfigent(nconf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		nssin.arg.nss.host.addr = (const char *)addr6;
		nssin.arg.nss.host.len = len;
		nssin.arg.nss.host.type = type;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			__IPv6_cleanup(buf);
			return (NULL);
		}
		free(buf);
		return (nssout.nss.host.hent);
	}
	/*
	 * If we got here, unknown type.
	 */
	*error_num = HOST_NOT_FOUND;
	return (NULL);
}
Example #29
0
/*
 * Reads a linux sockaddr and does any necessary translation.
 * Linux sockaddrs don't have a length field, only a family.
 * Copy the osockaddr structure pointed to by osa to kernel, adjust
 * family and convert to sockaddr.
 */
static int
linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
{
	struct sockaddr *sa;
	struct osockaddr *kosa;
#ifdef INET6
	struct sockaddr_in6 *sin6;
	int oldv6size;
#endif
	char *name;
	int bdom, error, hdrlen, namelen;

	if (salen < 2 || salen > UCHAR_MAX || !osa)
		return (EINVAL);

#ifdef INET6
	oldv6size = 0;
	/*
	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
	 * if it's a v4-mapped address, so reserve the proper space
	 * for it.
	 */
	if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
		salen += sizeof(uint32_t);
		oldv6size = 1;
	}
#endif

	kosa = malloc(salen, M_SONAME, M_WAITOK);

	if ((error = copyin(osa, kosa, salen)))
		goto out;

	bdom = linux_to_bsd_domain(kosa->sa_family);
	if (bdom == -1) {
		error = EAFNOSUPPORT;
		goto out;
	}

#ifdef INET6
	/*
	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
	 * which lacks the scope id compared with RFC2553 one. If we detect
	 * the situation, reject the address and write a message to system log.
	 *
	 * Still accept addresses for which the scope id is not used.
	 */
	if (oldv6size) {
		if (bdom == AF_INET6) {
			sin6 = (struct sockaddr_in6 *)kosa;
			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
			    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
				sin6->sin6_scope_id = 0;
			} else {
				log(LOG_DEBUG,
				    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
				error = EINVAL;
				goto out;
			}
		} else
			salen -= sizeof(uint32_t);
	}
#endif
	if (bdom == AF_INET) {
		if (salen < sizeof(struct sockaddr_in)) {
			error = EINVAL;
			goto out;
		}
		salen = sizeof(struct sockaddr_in);
	}

	if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
		hdrlen = offsetof(struct sockaddr_un, sun_path);
		name = ((struct sockaddr_un *)kosa)->sun_path;
		if (*name == '\0') {
			/*
		 	 * Linux abstract namespace starts with a NULL byte.
			 * XXX We do not support abstract namespace yet.
			 */
			namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
		} else
			namelen = strnlen(name, salen - hdrlen);
		salen = hdrlen + namelen;
		if (salen > sizeof(struct sockaddr_un)) {
			error = ENAMETOOLONG;
			goto out;
		}
	}
Example #30
0
/*
 * Copy the osockaddr structure pointed to by osa to kernel, adjust
 * family and convert to sockaddr.
 */
static int
do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
    struct malloc_type *mtype)
{
	int error=0, bdom;
	struct sockaddr *sa;
	struct osockaddr *kosa;
	int alloclen;
#ifdef INET6
	int oldv6size;
	struct sockaddr_in6 *sin6;
#endif

	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
		return (EINVAL);

	alloclen = *osalen;
#ifdef INET6
	oldv6size = 0;
	/*
	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
	 * if it's a v4-mapped address, so reserve the proper space
	 * for it.
	 */
	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
		alloclen = sizeof (struct sockaddr_in6);
		oldv6size = 1;
	}
#endif

	kosa = malloc(alloclen, mtype, M_WAITOK);

	if ((error = copyin(osa, kosa, *osalen)))
		goto out;

	bdom = linux_to_bsd_domain(kosa->sa_family);
	if (bdom == -1) {
		error = EAFNOSUPPORT;
		goto out;
	}

#ifdef INET6
	/*
	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
	 * which lacks the scope id compared with RFC2553 one. If we detect
	 * the situation, reject the address and write a message to system log.
	 *
	 * Still accept addresses for which the scope id is not used.
	 */
	if (oldv6size && bdom == AF_INET6) {
		sin6 = (struct sockaddr_in6 *)kosa;
		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
			sin6->sin6_scope_id = 0;
		} else {
			log(LOG_DEBUG,
			    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
			error = EINVAL;
			goto out;
		}
	} else
#endif
	if (bdom == AF_INET) {
		alloclen = sizeof(struct sockaddr_in);
		if (*osalen < alloclen) {
			error = EINVAL;
			goto out;
		}
	}

	sa = (struct sockaddr *) kosa;
	sa->sa_family = bdom;
	sa->sa_len = alloclen;

	*sap = sa;
	*osalen = alloclen;
	return (0);

out:
	free(kosa, mtype);
	return (error);
}