Exemple #1
0
gboolean
gdm_address_equal (GdmAddress *a,
                   GdmAddress *b)
{
        guint8 fam_a;
        guint8 fam_b;

        g_return_val_if_fail (a != NULL, FALSE);
        g_return_val_if_fail (a->ss != NULL, FALSE);
        g_return_val_if_fail (b != NULL, FALSE);
        g_return_val_if_fail (b->ss != NULL, FALSE);

        fam_a = a->ss->ss_family;
        fam_b = b->ss->ss_family;

        if (fam_a == AF_INET && fam_b == AF_INET) {
                return v4_v4_equal (SIN (a->ss), SIN (b->ss));
        }
#ifdef ENABLE_IPV6
        else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
                return v6_v6_equal (SIN6 (a->ss), SIN6 (b->ss));
        }
#endif
        return FALSE;
}
Exemple #2
0
int get_user6(	in_port_t lport,
				in_port_t fport,
				struct sockaddr_storage *laddr,
				struct sockaddr_storage *faddr)
{
	struct socket *sockp, sock;
	struct inpcbhead pcb6;
	int ret;

	ret = getbuf(kinfo->nl[N_TCB6].n_value, &pcb6, sizeof(pcb6));
	if (ret == -1)
		return (-1);

	sockp = getlist6(&pcb6, lport, fport,
				&SIN6(laddr)->sin6_addr, &SIN6(faddr)->sin6_addr);

	if (sockp == NULL)
		return (-1);

	ret = getbuf((u_long) sockp, &sock, sizeof(sock));
	if (ret == -1)
		return (-1);

	return (sock.so_uid);
}
Exemple #3
0
int get_user6(	in_port_t lport,
				in_port_t fport,
				struct sockaddr_storage *laddr,
				struct sockaddr_storage *faddr)
{
#if __NetBSD_Version__ >= 106250000	/* 1.6Y */
	struct socket *sockp, sock;
	struct inpcbtable tcbtable;
	int ret;
#ifdef SO_UIDINFO
	struct uidinfo uidinfo;
#endif

	ret = getbuf(kinfo->nl[N_TCB6].n_value, &tcbtable, sizeof(tcbtable));
	if (ret == -1)
		return (-1);

	sockp = getlist6(&tcbtable,
				(struct inpcbtable *) kinfo->nl[N_TCB6].n_value,
				lport, fport, &SIN6(laddr)->sin6_addr, &SIN6(faddr)->sin6_addr);
#else
	struct socket *sockp, sock;
	struct in6pcb tcb6;
	int ret;

	ret = getbuf(kinfo->nl[N_TCB6].n_value, &tcb6, sizeof(tcb6));
	if (ret == -1)
		return (-1);

	sockp = getlist6(&tcb6, lport, fport,
				&SIN6(laddr)->sin6_addr, &SIN6(faddr)->sin6_addr);
#endif

	if (sockp == NULL)
		return (-1);

	if (getbuf((u_long) sockp, &sock, sizeof(sock)) == -1)
		return (-1);

#ifdef SO_UIDINFO
	if (sock.so_uidinfo == NULL)
		return (-1);

	if (getbuf((u_long) sock.so_uidinfo, &uidinfo, sizeof(uidinfo)) == -1)
		return (-1);

	return (uidinfo.ui_uid);
#else
	return (sock.so_uid);
#endif
}
/**
 * gnome_vfs_address_get_sockaddr:
 * @address: A #GnomeVFSAddress
 * @port: A valid port in host byte order to set in the returned sockaddr
 * structure.
 * @len: A pointer to an int which will contain the length of the
 * return sockaddr structure.
 *
 * This function tanslates @address into a equivalent
 * sockaddr structure. The port specified at @port will
 * be set in the structure and @len will be set to the length
 * of the structure.
 * 
 * 
 * Return value: A newly allocated sockaddr structure the caller must free
 * or %NULL if @address did not point to a valid #GnomeVFSAddress.
 **/
struct sockaddr *
gnome_vfs_address_get_sockaddr (GnomeVFSAddress *address,
				guint16          port,
				int             *len)
{
	struct sockaddr *sa;

	g_return_val_if_fail (address != NULL, NULL);

	sa = g_memdup (address->sa, SA_SIZE (address->sa));

	switch (address->sa->sa_family) {
#ifdef ENABLE_IPV6
	case AF_INET6:
		SIN6 (sa)->sin6_port = g_htons (port);

		if (len != NULL) {
			*len = SIN6_LEN;
		}
		
		break;
#endif
	case AF_INET:
		SIN (sa)->sin_port = g_htons (port);

		if (len != NULL) {
			*len = SIN_LEN;
		}
		break;

	}

	return sa;
}
Exemple #5
0
/*
 * Converts the internet address plus port string in 'St'
 * into their network byte order representations.
 *
 * returns: - 0 -> conversion failed
 *          - 1 -> only address part returned (inaddrPt)
 *          - 2 -> address and port returned
 *
 */
static void getSockAdr(struct sockaddr *SaPt, socklen_t * SaLenPt, char *AddrSt, char *PortSt)
{
	struct sockaddr_in *Sin4;
	struct sockaddr_in6 *Sin6;

	if (strchr(AddrSt, ':') == NULL) {
		Sin4 = SIN4(SaPt);
		memset(Sin4, 0, sizeof(*Sin4));

		Sin4->sin_family = AF_INET;
		Sin4->sin_port = htons(atoi(PortSt));

		if (inet_pton(AF_INET, AddrSt, &Sin4->sin_addr) <= 0) {
			smclog(LOG_ERR, "inet_pton failed for address %s: %m", AddrSt);
			exit(255);
		}

		*SaLenPt = sizeof(struct sockaddr_in);
	} else {
		Sin6 = SIN6(SaPt);
		memset(Sin6, 0, sizeof(*Sin6));

		Sin6->sin6_family = AF_INET6;
		Sin6->sin6_port = htons(atoi(PortSt));

		if (inet_pton(AF_INET6, AddrSt, &Sin6->sin6_addr) <= 0) {
			smclog(LOG_ERR, "inet_pton failed for address %s: %m", AddrSt);
			exit(255);
		}

		*SaLenPt = sizeof(struct sockaddr_in6);
	}
}
Exemple #6
0
struct in6_addr *
get_addr(char *buf)
{
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
	struct sockaddr *sa, *rti_info[RTAX_MAX];

	sa = (struct sockaddr *)(rtm + 1);
	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);

	return (&SIN6(rti_info[RTAX_DST])->sin6_addr);
}
Exemple #7
0
int
get_prefixlen(char *buf)
{
	struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
	struct sockaddr *sa, *rti_info[RTAX_MAX];
	char *p, *lim;

	sa = (struct sockaddr *)(rtm + 1);
	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
	sa = rti_info[RTAX_NETMASK];

	p = (char *)(&SIN6(sa)->sin6_addr);
	lim = (char *)sa + sa->sa_len;
	return prefixlen(p, lim);
}
/**
 * gnome_vfs_address_equal:
 * @a: A #GnomeVFSAddress
 * @b: A #GnomeVFSAddress to compare with @a
 *
 * Compares two #GnomeVFSAddress objects and returns TRUE if they have the
 * addresses are equal as well as the address family type. 
 * 
 * Return value: TRUE if the two addresses match.
 *
 * Since: 2.14 
 **/
gboolean
gnome_vfs_address_equal (const GnomeVFSAddress *a,
			 const GnomeVFSAddress *b)
{
	guint8 fam_a;
       	guint8 fam_b;

	g_return_val_if_fail (a != NULL || a->sa != NULL, FALSE);
	g_return_val_if_fail (b != NULL || b->sa != NULL, FALSE);

	
	fam_a = a->sa->sa_family;
	fam_b = b->sa->sa_family;

	if (fam_a == AF_INET && fam_b == AF_INET) {
		return v4_v4_equal (SIN (a->sa), SIN (b->sa));		
	}
#ifdef ENABLE_IPV6
	else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
		return v6_v6_equal (SIN6 (a->sa), SIN6 (b->sa));
	}	
#endif
	return FALSE;
}
/**
 * gnome_vfs_address_to_string:
 * @address: A pointer to a #GnomeVFSAddress
 * 
 * Translate @address to a printable string.
 * 
 * Returns: A newly alloced string representation of @address which
 * the caller must free.
 *
 * Since: 2.8
 **/
char *
gnome_vfs_address_to_string (GnomeVFSAddress *address)
{
#ifdef G_OS_WIN32
	char text_addr[100];
	DWORD text_length = sizeof (text_addr);

	if (WSAAddressToString (address->sa, SA_SIZE (address->sa),
				NULL, text_addr, &text_length) == 0)
		return g_strdup (text_addr);

	return NULL;
#else
	const char *text_addr;
#ifdef HAVE_INET_NTOP
	char buf[MAX_ADDRSTRLEN];
#endif	
	g_return_val_if_fail (address != NULL, NULL);

	text_addr = NULL;

	switch (address->sa->sa_family) {
#if defined (ENABLE_IPV6) && defined (HAVE_INET_NTOP)	
	case AF_INET6:
			 
		text_addr = inet_ntop (AF_INET6,
				       &SIN6 (address->sa)->sin6_addr,
				       buf,
				       sizeof (buf));
		break;
#endif
	case AF_INET:
#if HAVE_INET_NTOP
		text_addr = inet_ntop (AF_INET,
				       &SIN (address->sa)->sin_addr,
				       buf,
				       sizeof (buf));
#else
		text_addr = inet_ntoa (SIN (address->sa)->sin_addr);
#endif  /* HAVE_INET_NTOP */
		break;
	}
	   
	  
	return text_addr != NULL ? g_strdup (text_addr) : NULL;
#endif
}
/**
 * gnome_vfs_address_match:
 * @a: A #GnomeVFSAddress
 * @b: A #GnomeVFSAddress to compare with @a
 * @prefix: Number of bits to take into account starting
 * from the left most one.
 * 
 * Matches the first @prefix number of bits of two given #GnomeVFSAddress 
 * objects and returns TRUE of they match otherwise FALSE. This function can
 * also match mapped address (i.e. IPv4 mapped IPv6 addresses).
 * 
 * Return value: TRUE if the two addresses match.
 *
 * Since: 2.14 
 **/
gboolean
gnome_vfs_address_match (const GnomeVFSAddress *a,
			 const GnomeVFSAddress *b,
			 guint                  prefix)
{
	guint8 fam_a;
       	guint8 fam_b;

	g_return_val_if_fail (a != NULL || a->sa != NULL, FALSE);
	g_return_val_if_fail (b != NULL || b->sa != NULL, FALSE);

	fam_a = a->sa->sa_family;
	fam_b = b->sa->sa_family;

	if (fam_a == AF_INET && fam_b == AF_INET) {
		if (prefix == 0 || prefix > 31) {
			return v4_v4_equal (SIN (a->sa), SIN (b->sa));
		} else {
			return v4_v4_match (SIN (a->sa), SIN (b->sa), prefix);
		}		
	}
#ifdef ENABLE_IPV6
	else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
		if (prefix == 0 || prefix > 127) {
			return v6_v6_equal (SIN6 (a->sa), SIN6 (b->sa));
		} else {
			return v6_v6_match (SIN6 (a->sa), SIN6 (b->sa), prefix);
		}
	} else if (fam_a == AF_INET && fam_b == AF_INET6) {
		return v4_v6_match (SIN (a->sa), SIN6 (b->sa), prefix);
	} else if (fam_a == AF_INET6 && fam_b == AF_INET) {
		return v4_v6_match (SIN (b->sa), SIN6 (a->sa), prefix);
	} 
#endif

	/* This is the case when we are trying to compare unkown family types */
	g_assert_not_reached ();
	return FALSE;
}
Exemple #11
0
int sock_listen(struct sockaddr_storage *ss, in_port_t listen_port) {
	int sock;
	struct addrinfo *cur;
	const int one = 1;

	if (ss == NULL)
		return (-1);

	cur = xcalloc(1, sizeof(*cur));
	cur->ai_family = ss->ss_family;

	switch (cur->ai_family) {
		case AF_INET6:
			cur->ai_addrlen = sizeof(struct sockaddr_in6);
			break;

		case AF_INET:
			cur->ai_addrlen = sizeof(struct sockaddr_in);
			break;

		default:
			debug("unknown family: %d", cur->ai_family);
			free(cur);
			return (-1);
	}

	cur->ai_addr = xmalloc(cur->ai_addrlen);
	memcpy(cur->ai_addr, ss, cur->ai_addrlen);

	if (cur->ai_family == AF_INET)
		SIN4(cur->ai_addr)->sin_port = htons(listen_port);
	else
		SIN6(cur->ai_addr)->sin6_port = htons(listen_port);

	sock = socket(cur->ai_family, SOCK_STREAM, 0);
	if (sock == -1) {
		debug("socket: %s", strerror(errno));
		goto done;
	}

	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) {
		debug("setsockopt: %s", strerror(errno));
		close(sock);
		sock = -1;
		goto done;
	}

	if (bind(sock, cur->ai_addr, cur->ai_addrlen) != 0) {
		debug("bind: %s", strerror(errno));
		close(sock);
		sock = -1;
		goto done;
	}

	if (listen(sock, SOMAXCONN) != 0) {
		debug("listen: %s", strerror(errno));
		close(sock);
		sock = -1;
		goto done;
	}

#ifndef WIN32
	if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
		debug("fcntl: %s", strerror(errno));
		close(sock);
		sock = -1;
	}
#endif

done:
	free(cur->ai_addr);
	free(cur);
	return (sock);
}
Exemple #12
0
char *
get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
{
	struct rt_msghdr *rtm;
	struct ifa_msghdr *ifam;
	struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];

	*lenp = 0;
	for (rtm = (struct rt_msghdr *)buf;
	     rtm < (struct rt_msghdr *)lim;
	     rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
		/* just for safety */
		if (!rtm->rtm_msglen) {
			syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
			    "(buf=%p lim=%p rtm=%p)", __func__,
			    buf, lim, rtm);
			break;
		}
		if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
			syslog(LOG_WARNING,
			    "<%s> routing message version mismatch "
			    "(buf=%p lim=%p rtm=%p)", __func__,
			    buf, lim, rtm);
			continue;
		}

		if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
			continue;

		switch (rtm->rtm_type) {
		case RTM_GET:
		case RTM_ADD:
		case RTM_DELETE:
			/* address related checks */
			sa = (struct sockaddr *)(rtm + 1);
			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
			if ((dst = rti_info[RTAX_DST]) == NULL ||
			    dst->sa_family != AF_INET6)
				continue;

			if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
			    IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
				continue;

			if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
			    gw->sa_family != AF_LINK)
				continue;
			if (ifindex && SDL(gw)->sdl_index != ifindex)
				continue;

			if (rti_info[RTAX_NETMASK] == NULL)
				continue;

			/* found */
			*lenp = rtm->rtm_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		case RTM_NEWADDR:
		case RTM_DELADDR:
			ifam = (struct ifa_msghdr *)rtm;

			/* address related checks */
			sa = (struct sockaddr *)(ifam + 1);
			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
			if ((ifa = rti_info[RTAX_IFA]) == NULL ||
			    (ifa->sa_family != AF_INET &&
			     ifa->sa_family != AF_INET6))
				continue;

			if (ifa->sa_family == AF_INET6 &&
			    (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
			     IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
				continue;

			if (ifindex && ifam->ifam_index != ifindex)
				continue;

			/* found */
			*lenp = ifam->ifam_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		case RTM_IFINFO:
		case RTM_IFANNOUNCE:
			/* found */
			*lenp = rtm->rtm_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		}
	}

	return ((char *)rtm);
}
Exemple #13
0
	sin->sin_family = AF_INET;

	if (inet_aton(s, &sin->sin_addr))
		;
	else if ((hp = gethostbyname(s)) != NULL)
		bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
	else if ((np = getnetbyname(s)) != NULL)
		sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
	else
		errx(1, "%s: bad value", s);
}

#ifdef INET6
#define SIN6(x) ((struct sockaddr_in6 *) &(x))
struct sockaddr_in6 *sin6tab[] = {
SIN6(in6_addreq.ifra_addr), SIN6(in6_addreq.ifra_dstaddr)};

void
in6_getaddr(char *s, int which)
{
	struct sockaddr_in6 *sin = sin6tab[which];

	sin->sin6_len = sizeof(*sin);
	sin->sin6_family = AF_INET6;

        if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
		errx(1, "%s: bad value", s);
}

void
in6_getprefix(char *plen, int which)
Exemple #14
0
/* compares a host to an allowed sender list entry. Handles all subleties
 * including IPv4/v6 as well as domain name wildcards.
 * This is a helper to isAllowedSender.
 * Returns 0 if they do not match, 1 if they match and 2 if a DNS name would have been required.
 * contributed 2007-07-16 by [email protected]
 */
static int
MaskCmp(struct NetAddr *pAllow, uint8_t bits, struct sockaddr *pFrom, const char *pszFromHost, int bChkDNS)
{
	assert(pAllow != NULL);
	assert(pFrom != NULL);

	if(F_ISSET(pAllow->flags, ADDR_NAME)) {
		if(bChkDNS == 0)
			return 2;
		dbgprintf("MaskCmp: host=\"%s\"; pattern=\"%s\"\n", pszFromHost, pAllow->addr.HostWildcard);
		
#		if !defined(FNM_CASEFOLD)
			/* TODO: I don't know if that then works, seen on HP UX, what I have not in lab... ;) */
			return(fnmatch(pAllow->addr.HostWildcard, pszFromHost, FNM_NOESCAPE) == 0);
#		else
			return(fnmatch(pAllow->addr.HostWildcard, pszFromHost, FNM_NOESCAPE|FNM_CASEFOLD) == 0);
#		endif
	} else {/* We need to compare an IP address */
		switch (pFrom->sa_family) {
		case AF_INET:
			if (AF_INET == pAllow->addr.NetAddr->sa_family)
				return(( SIN(pFrom)->sin_addr.s_addr & htonl(0xffffffff << (32 - bits)) )
				       == SIN(pAllow->addr.NetAddr)->sin_addr.s_addr);
			else
				return 0;
			break;
		case AF_INET6:
			switch (pAllow->addr.NetAddr->sa_family) {
			case AF_INET6: {
				struct in6_addr ip, net;
				register uint8_t i;
				
				memcpy (&ip,  &(SIN6(pFrom))->sin6_addr, sizeof (struct in6_addr));
				memcpy (&net, &(SIN6(pAllow->addr.NetAddr))->sin6_addr, sizeof (struct in6_addr));
				
				i = bits/32;
				if (bits % 32)
					ip.s6_addr32[i++] &= htonl(0xffffffff << (32 - (bits % 32)));
				for (; i < (sizeof ip.s6_addr32)/4; i++)
					ip.s6_addr32[i] = 0;
				
				return (memcmp (ip.s6_addr, net.s6_addr, sizeof ip.s6_addr) == 0 &&
					(SIN6(pAllow->addr.NetAddr)->sin6_scope_id != 0 ?
					 SIN6(pFrom)->sin6_scope_id == SIN6(pAllow->addr.NetAddr)->sin6_scope_id : 1));
			}
			case AF_INET: {
				struct in6_addr *ip6 = &(SIN6(pFrom))->sin6_addr;
				struct in_addr  *net = &(SIN(pAllow->addr.NetAddr))->sin_addr;
				
				if ((ip6->s6_addr32[3] & (u_int32_t) htonl((0xffffffff << (32 - bits)))) == net->s_addr &&
#if BYTE_ORDER == LITTLE_ENDIAN
				    (ip6->s6_addr32[2] == (u_int32_t)0xffff0000) &&
#else
				    (ip6->s6_addr32[2] == (u_int32_t)0x0000ffff) &&
#endif
				    (ip6->s6_addr32[1] == 0) && (ip6->s6_addr32[0] == 0))
					return 1;
				else
					return 0;
			}
			default:
				/* Unsupported AF */
				return 0;
			}
		default:
			/* Unsupported AF */
			return 0;
		}
	}
}
Exemple #15
0
/* function to add an allowed sender to the allowed sender list. The
 * root of the list is caller-provided, so it can be used for all
 * supported lists. The caller must provide a pointer to the root,
 * as it eventually needs to be updated. Also, a pointer to the
 * pointer to the last element must be provided (to speed up adding
 * list elements).
 * rgerhards, 2005-09-26
 * If a hostname is given there are possible multiple entries
 * added (all addresses from that host).
 */
static rsRetVal AddAllowedSender(struct AllowedSenders **ppRoot, struct AllowedSenders **ppLast,
		     		 struct NetAddr *iAllow, uint8_t iSignificantBits)
{
	DEFiRet;

	assert(ppRoot != NULL);
	assert(ppLast != NULL);
	assert(iAllow != NULL);

	if (!F_ISSET(iAllow->flags, ADDR_NAME)) {
		if(iSignificantBits == 0)
			/* we handle this seperatly just to provide a better
			 * error message.
			 */
			errmsg.LogError(0, NO_ERRCODE, "You can not specify 0 bits of the netmask, this would "
				 "match ALL systems. If you really intend to do that, "
				 "remove all $AllowedSender directives.");
		
		switch (iAllow->addr.NetAddr->sa_family) {
		case AF_INET:
			if((iSignificantBits < 1) || (iSignificantBits > 32)) {
				errmsg.LogError(0, NO_ERRCODE, "Invalid number of bits (%d) in IPv4 address - adjusted to 32",
					    (int)iSignificantBits);
				iSignificantBits = 32;
			}
			
			MaskIP4 (&(SIN(iAllow->addr.NetAddr)->sin_addr), iSignificantBits);
			break;
		case AF_INET6:
			if((iSignificantBits < 1) || (iSignificantBits > 128)) {
				errmsg.LogError(0, NO_ERRCODE, "Invalid number of bits (%d) in IPv6 address - adjusted to 128",
					    iSignificantBits);
				iSignificantBits = 128;
			}

			MaskIP6 (&(SIN6(iAllow->addr.NetAddr)->sin6_addr), iSignificantBits);
			break;
		default:
			/* rgerhards, 2007-07-16: We have an internal program error in this
			 * case. However, there is not much we can do against it right now. Of
			 * course, we could abort, but that would probably cause more harm
			 * than good. So we continue to run. We simply do not add this line - the
			 * worst thing that happens is that one host will not be allowed to
			 * log.
			 */
			errmsg.LogError(0, NO_ERRCODE, "Internal error caused AllowedSender to be ignored, AF = %d",
				    iAllow->addr.NetAddr->sa_family);
			ABORT_FINALIZE(RS_RET_ERR);
		}
		/* OK, entry constructed, now lets add it to the ACL list */
		iRet = AddAllowedSenderEntry(ppRoot, ppLast, iAllow, iSignificantBits);
	} else {
		/* we need to process a hostname ACL */
		if(glbl.GetDisableDNS()) {
			errmsg.LogError(0, NO_ERRCODE, "Ignoring hostname based ACLs because DNS is disabled.");
			ABORT_FINALIZE(RS_RET_OK);
		}
		
		if (!strchr (iAllow->addr.HostWildcard, '*') &&
		    !strchr (iAllow->addr.HostWildcard, '?') &&
		    ACLDontResolve == 0) {
			/* single host - in this case, we pull its IP addresses from DNS
			* and add IP-based ACLs.
			*/
			struct addrinfo hints, *res, *restmp;
			struct NetAddr allowIP;
			
			memset (&hints, 0, sizeof (struct addrinfo));
			hints.ai_family = AF_UNSPEC;
			hints.ai_socktype = SOCK_DGRAM;
#			ifdef AI_ADDRCONFIG /* seems not to be present on all systems */
				hints.ai_flags  = AI_ADDRCONFIG;
#			endif

			if (getaddrinfo (iAllow->addr.HostWildcard, NULL, &hints, &res) != 0) {
			        errmsg.LogError(0, NO_ERRCODE, "DNS error: Can't resolve \"%s\"", iAllow->addr.HostWildcard);
				
				if (ACLAddHostnameOnFail) {
				        errmsg.LogError(0, NO_ERRCODE, "Adding hostname \"%s\" to ACL as a wildcard entry.", iAllow->addr.HostWildcard);
				        iRet = AddAllowedSenderEntry(ppRoot, ppLast, iAllow, iSignificantBits);
					FINALIZE;
				} else {
				        errmsg.LogError(0, NO_ERRCODE, "Hostname \"%s\" WON\'T be added to ACL.", iAllow->addr.HostWildcard);
				        ABORT_FINALIZE(RS_RET_NOENTRY);
				}
			}
			
			for (restmp = res ; res != NULL ; res = res->ai_next) {
				switch (res->ai_family) {
				case AF_INET: /* add IPv4 */
					iSignificantBits = 32;
					allowIP.flags = 0;
					if((allowIP.addr.NetAddr = MALLOC(res->ai_addrlen)) == NULL) {
						ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
					}
					memcpy(allowIP.addr.NetAddr, res->ai_addr, res->ai_addrlen);
					
					if((iRet = AddAllowedSenderEntry(ppRoot, ppLast, &allowIP, iSignificantBits))
						!= RS_RET_OK) {
						free(allowIP.addr.NetAddr);
						FINALIZE;
					}
					break;
				case AF_INET6: /* IPv6 - but need to check if it is a v6-mapped IPv4 */
					if(IN6_IS_ADDR_V4MAPPED (&SIN6(res->ai_addr)->sin6_addr)) {
						/* extract & add IPv4 */
						
						iSignificantBits = 32;
						allowIP.flags = 0;
						if((allowIP.addr.NetAddr = (struct sockaddr *) MALLOC(sizeof(struct sockaddr)))
						    == NULL) {
							ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
						}
						SIN(allowIP.addr.NetAddr)->sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN    
                                                SIN(allowIP.addr.NetAddr)->sin_len    = sizeof (struct sockaddr_in);
#endif
						SIN(allowIP.addr.NetAddr)->sin_port   = 0;
						memcpy(&(SIN(allowIP.addr.NetAddr)->sin_addr.s_addr),
							&(SIN6(res->ai_addr)->sin6_addr.s6_addr32[3]),
							sizeof (in_addr_t));

						if((iRet = AddAllowedSenderEntry(ppRoot, ppLast, &allowIP,
								iSignificantBits))
							!= RS_RET_OK) {
							free(allowIP.addr.NetAddr);
							FINALIZE;
						}
					} else {
						/* finally add IPv6 */
						
						iSignificantBits = 128;
						allowIP.flags = 0;
						if((allowIP.addr.NetAddr = MALLOC(res->ai_addrlen)) == NULL) {
							ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
						}
						memcpy(allowIP.addr.NetAddr, res->ai_addr, res->ai_addrlen);
						
						if((iRet = AddAllowedSenderEntry(ppRoot, ppLast, &allowIP,
								iSignificantBits))
							!= RS_RET_OK) {
							free(allowIP.addr.NetAddr);
							FINALIZE;
						}
					}
					break;
				}
			}
			freeaddrinfo (restmp);
		} else {
			/* wildcards in hostname - we need to add a text-based ACL.
			 * For this, we already have everything ready and just need
			 * to pass it along...
			 */
			iRet =  AddAllowedSenderEntry(ppRoot, ppLast, iAllow, iSignificantBits);
		}
	}

finalize_it:
	RETiRet;
}
Exemple #16
0
static struct socket *getlist(	void *arg,
								in_port_t lport,
								in_port_t fport,
								const struct sockaddr *local,
								const struct sockaddr *remote)
{
	struct inpcb *head, pcbp;
	struct inpcbhead *pcbhead = arg;
	char *faddr, *laddr, *pfaddr, *pladdr;
	int alen;

	if (remote->sa_family != local->sa_family)
		return (NULL);
	switch (remote->sa_family) {
	case AF_INET:
		faddr = (char *)&SIN4(remote)->sin_addr;
		laddr = (char *)&SIN4(local)->sin_addr;
		break;
	case AF_INET6:
		faddr = (char *)&SIN6(remote)->sin6_addr;
		laddr = (char *)&SIN6(local)->sin6_addr;
		break;
	default:
		return (NULL);
	}

	head = pcbhead->lh_first;
	if (head == NULL)
		return (NULL);

	do {
		if (getbuf((u_long) head, &pcbp, sizeof(struct inpcb)) == -1)
			break;

		if (opt_enabled(PROXY) && remote->sa_family == AF_INET) {
			if (SIN4(remote)->sin_addr.s_addr == SIN4(&proxy)->sin_addr.s_addr &&
				SIN4(local)->sin_addr.s_addr != SIN4(&proxy)->sin_addr.s_addr &&
				pcbp.inp_fport == fport &&
				pcbp.inp_lport == lport)
			{
				return (pcbp.inp_socket);
			}
		}

		if (remote->sa_family == AF_INET)
		{
			pfaddr = (char *)&pcbp.inp_faddr;
			pladdr = (char *)&pcbp.inp_laddr;
			alen = sizeof(struct in_addr);
		}
		else if (remote->sa_family == AF_INET6)
		{
			pfaddr = (char *)&pcbp.in6p_faddr;
			pladdr = (char *)&pcbp.in6p_laddr;
			alen = sizeof(struct in6_addr);
		}
		else
			continue;
		if (memcmp(pfaddr, faddr, alen) == 0 &&
			memcmp(pladdr, laddr, alen) == 0 &&
			pcbp.inp_fport == fport &&
			pcbp.inp_lport == lport)
		{
			return (pcbp.inp_socket);
		}

		head = pcbp.inp_list.le_next;
	} while (head != NULL);

	return (NULL);
}
Exemple #17
0
/* Retrieve address information for the given ifp */
static int
if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label)
{
  int ret;
  struct lifreq lifreq;
  struct sockaddr_storage mask, dest;
  char *dest_pnt = NULL;
  u_char prefixlen = 0;
  afi_t af;
  int flags = 0;

  /* Interface's name and address family.
   * We need to use the logical interface name / label, if we've been
   * given one, in order to get the right address
   */
  strncpy (lifreq.lifr_name, (label ? label : ifp->name), IFNAMSIZ);

  /* Interface's address. */
  memcpy (&lifreq.lifr_addr, addr, ADDRLEN (addr));
  af = addr->sa_family;

  /* Point to point or broad cast address pointer init. */
  dest_pnt = NULL;

  if (AF_IOCTL (af, SIOCGLIFDSTADDR, (caddr_t) & lifreq) >= 0)
    {
      memcpy (&dest, &lifreq.lifr_dstaddr, ADDRLEN (addr));
      if (af == AF_INET)
        dest_pnt = (char *) &(SIN (&dest)->sin_addr);
      else
        dest_pnt = (char *) &(SIN6 (&dest)->sin6_addr);
      flags = ZEBRA_IFA_PEER;
    }

  if (af == AF_INET)
    {
      ret = if_ioctl (SIOCGLIFNETMASK, (caddr_t) & lifreq);
      
      if (ret < 0)
        {
          if (errno != EADDRNOTAVAIL)
            {
              zlog_warn ("SIOCGLIFNETMASK (%s) fail: %s", ifp->name,
                         safe_strerror (errno));
              return ret;
            }
          return 0;
        }
      memcpy (&mask, &lifreq.lifr_addr, ADDRLEN (addr));

      prefixlen = ip_masklen (SIN (&mask)->sin_addr);
      if (!dest_pnt && (if_ioctl (SIOCGLIFBRDADDR, (caddr_t) & lifreq) >= 0))
	{
          memcpy (&dest, &lifreq.lifr_broadaddr, sizeof (struct sockaddr_in));
          dest_pnt = (char *) &SIN (&dest)->sin_addr;
        }
    }
#ifdef HAVE_IPV6
  else if (af == AF_INET6)
    {
      if (if_ioctl_ipv6 (SIOCGLIFSUBNET, (caddr_t) & lifreq) < 0)
	{
	  if (ifp->flags & IFF_POINTOPOINT)
	    prefixlen = IPV6_MAX_BITLEN;
	  else
	    zlog_warn ("SIOCGLIFSUBNET (%s) fail: %s",
		       ifp->name, safe_strerror (errno));
	}
      else
	{
	  prefixlen = lifreq.lifr_addrlen;
	}
    }
#endif /* HAVE_IPV6 */

  /* Set address to the interface. */
  if (af == AF_INET)
    connected_add_ipv4 (ifp, flags, &SIN (addr)->sin_addr, prefixlen,
                        (struct in_addr *) dest_pnt, label);
#ifdef HAVE_IPV6
  else if (af == AF_INET6)
    connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen,
                        (struct in6_addr *) dest_pnt, label);
#endif /* HAVE_IPV6 */

  return 0;
}
/*FUNCTION*-------------------------------------------------------------
*
* Function Name   : getaddrinfo
* Returned Value  : RTCS_OK or error code
* Comments        :
*        Get a list of IP addresses and port numbers for host hostname and service servname.
*
*END*-----------------------------------------------------------------*/
int32_t getaddrinfo
(
	const char 				*hostname, 	/* host name or IP or NULL							*/
	const char 				*servname,	/* service name or port number						*/
	const struct addrinfo 	*hints,		/* set flags										*/
	struct addrinfo 		**res		/* [OUT]list of address structures					*/
)

{
	const char 		*proto = NULL;
	int 			family; 
	int				socktype; 
	int				flags; 
	int				protocol;
	
	struct addrinfo *ai;
	struct addrinfo *ai_list;
	uint16_t port; 
	uint16_t err; 
	uint16_t i;
	
	
	int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,int, int);

	/*hostname and send name can not be NULL in same time*/
	if (hostname == NULL && servname == NULL)
	{
		return (EAI_NONAME);
	}

	proto = NULL;
	if (hints != NULL) 
	{
		if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
		{
			return (EAI_BADFLAGS);
		}
		if (hints->ai_addrlen || hints->ai_canonname || hints->ai_addr || hints->ai_next) 
		{
			_task_errno = MQX_EINVAL;
			return (EAI_SYSTEM);
	    }

		family = hints->ai_family;
		socktype = hints->ai_socktype;
		protocol = hints->ai_protocol;
		flags = hints->ai_flags;
		
		/* looking for correct protocol depended on family and socket type */
		switch (family) {

			case AF_UNSPEC:
        #if RTCSCFG_ENABLE_IP4
			case AF_INET:
        #endif
        #if RTCSCFG_ENABLE_IP6
			case AF_INET6:
        #endif
				if(hints->ai_socktype == 0)
				{
					break;
			
				}else if(hints->ai_socktype == SOCK_STREAM)	{
				
					proto = "tcp";
				
				}else if(hints->ai_socktype == SOCK_DGRAM)	{
					
					proto = "udp";
			
				}else{
					return (EAI_SOCKTYPE);
				}
			break;

		default:
			return (EAI_FAMILY);

		}/* end of  switch (family) */
	} else {
	
		protocol = 0;
		family = 0;
		socktype = 0;
		flags = 0;
	
	}/* end of (hints != NULL) */

	if(proto !=NULL)
	{
		protocol = (strcmp(proto,"tcp")) ? 2 : 1;

	}

	/*
	 * Ok, only AF_INET and AF_INET6 left.
	 */
	 
	/*************************************/

	/*
	 * First, look up the service port if it was
	 * requested.  If the socket type wasn't specified, then
	 * try and figure it out.
	 */
	if (servname != NULL) {
		char *e;

		port = strtol(servname, &e, 10);
		if (*e == '\0')                     //*e - end pointer
		{   /* Port number.*/
 			if (socktype == 0)				//Not sure that it is necessary here
			{
				return (EAI_SOCKTYPE);
			}
			/* When port will be in network endian, do mqx_htons(&tmp,(uint16_t) port);   */
		}
		else
		{
			/* We use only port number. We do not use a service name */
			return (EAI_SERVICE);			
		}/*end of (*e == '\0')*/
	}
	else
	{
		port = 0;
	} /* end (servname != NULL)	*/

	/*
	 * Next, deal with just a service name, and no hostname.
	 * (we verified that one of them was non-null up above).
	 */
	
	ai_list = NULL;
				 
	if (hostname == NULL && (flags & AI_PASSIVE) != 0) 
	{
    #if RTCSCFG_ENABLE_IP4
	    if (family == AF_INET || family == 0) 
		{
		
			/* Allocate an addrinfo structure, and a sockaddr structure */		
			ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));

			if (ai == NULL)
			{
				freeaddrinfo(ai_list);
				return (EAI_MEMORY);
			}
			ai->ai_socktype = socktype;
			ai->ai_protocol = protocol;
			SIN(ai->ai_addr)->sin_port = port;
			ai->ai_next = ai_list;
			ai_list = ai;
		}
    #endif
    #if RTCSCFG_ENABLE_IP6
		if (family == AF_INET6 || family == 0) 
		{
			ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
			if (ai == NULL) 
			{
				freeaddrinfo(ai_list);
				return (EAI_MEMORY);
			}
			ai->ai_socktype = socktype;
			ai->ai_protocol = protocol;
			SIN6(ai->ai_addr)->sin6_port = port;
			ai->ai_next = ai_list;
			ai_list = ai;
		}
    #endif

		*res = ai;
		return (0);
	}/* end of (hostname == NULL && (flags & AI_PASSIVE) != 0) */


	/*
	 * If the host is not NULL and the family isn't specified or AI_NUMERICHOST 
	 * specified, check first to see if it is a numeric address.
	 * Though the gethostbyname2() routine
	 * will recognize numeric addresses, it will only recognize
	 * the format that it is being called for.  Thus, a numeric
	 * AF_INET address will be treated by the AF_INET6 call as
	 * a domain name, and vice versa.  Checking for both numerics
	 * here avoids that.
	 */
	if (hostname != NULL && (family == 0 || (flags & AI_NUMERICHOST) != 0)) 
	{
		char abuf[sizeof(struct in6_addr)];
		char nbuf[NI_MAXHOST];
		int addrsize, addroff;
		char *p, *ep;
		char ntmp[NI_MAXHOST];
		uint32_t scopeid;

		/*
		 * Scope identifier portion.
		 * scope id must be a decimal number
		 */
		ntmp[0] = '\0';
		if (strchr(hostname, '%') != NULL) 
		{
			strncpy(ntmp, hostname, sizeof(ntmp) - 1);
			ntmp[sizeof(ntmp) - 1] = '\0';
            /*Returns a pointer to the first occurrence of character '%'.*/			
			p = strchr(ntmp, '%');
			ep = NULL;

			/*
			 * Vendors may want to support non-numeric
			 * scopeid around here.
			 */

			if (p != NULL)
			{
				scopeid = (uint32_t)strtoul(p + 1, &ep, 10);
			}				
			if (p != NULL && ep != NULL && ep[0] == '\0')
			{
				*p = '\0';
			}else {
				ntmp[0] = '\0';
				scopeid = 0;
			}
		} else{
			scopeid = 0;
		} /* end of  (strchr(hostname, '%') != NULL) */	


		  /*
	 	   * Converts a human readable IP address into an address 
	 	   * family appropriate 32bit or 128bit binary structure.
	 	   */
	    if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf,sizeof( *((struct in_addr *)abuf)))== RTCS_OK)
	    {
			if (family == AF_INET6) 
			{
				/*
			 	 * Convert to a V4 mapped address.
			 	 */
				struct in6_addr *a6 = (struct in6_addr *)abuf;
				memcpy(&a6->s6_addr[12], &a6->s6_addr[0], 4);
				memset(&a6->s6_addr[10], 0xff, 2);
				memset(&a6->s6_addr[0], 0, 10);
				goto inet6_addr;
			}
			addrsize = sizeof(struct in_addr);
			addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
			family = AF_INET;
			goto common;
		} else if (ntmp[0] != '\0' && inet_pton(AF_INET6, ntmp, abuf,sizeof(struct in6_addr)) == RTCS_OK)
		{
			if (family && family != AF_INET6)
			{
				return (EAI_NONAME);
			}
			addrsize = sizeof(struct in6_addr);
			addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
			family = AF_INET6;
			goto common;
		} else if (inet_pton(AF_INET6, hostname, abuf,sizeof(struct in6_addr)) == RTCS_OK) 
		{
			if (family != 0 && family != AF_INET6)
			{
				return (EAI_NONAME);
			}
inet6_addr:
			addrsize = sizeof(struct in6_addr);
			addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
			family = AF_INET6;

common:
			ai = ai_clone(ai_list, family);
			if (ai == NULL)
			{
				return (EAI_MEMORY);
			}
			ai_list = ai;
			ai->ai_socktype = socktype;
			//ai->ai_protocol = protocol;
			SIN(ai->ai_addr)->sin_port = port;
			memcpy((char *)ai->ai_addr + addroff, abuf, addrsize);

			if (flags & AI_CANONNAME) 
			{

				if (ai->ai_family == AF_INET6)
				{
					SIN6(ai->ai_addr)->sin6_scope_id = scopeid;
				}	

				if (getnameinfo(	ai->ai_addr,
			    					ai->ai_addrlen, 
			    					nbuf, 
			    					sizeof(nbuf),
					      			NULL, 
					      			0,
					      			NI_NUMERICHOST
					       		) == 0) 
				{
					ai->ai_canonname = strdup(nbuf);
					if (ai->ai_canonname == NULL) 
					{
						freeaddrinfo(ai_list);
						return (EAI_MEMORY);
					}
				} else 	
				{
					/* XXX raise error? */
					ai->ai_canonname = NULL;
				}
			}/*end of (flags & AI_CANONNAME)*/
			goto done;
		} else if ((flags & AI_NUMERICHOST) != 0) 
		{
			return (EAI_NONAME);
		}
	}/* end of (inet_pton(AF_INET, hostname, (struct in_addr *)abuf)== 1) */

	set_order(family, net_order);
	for (i = 0; i < FOUND_MAX; i++) {
		if (net_order[i] == NULL)
			break;
		err = (net_order[i])(hostname, flags, &ai_list,
				     socktype, port);
		if (err != 0)
			return (err);
	}

	if (ai_list == NULL)
		return (EAI_NODATA);

done:
	ai_list->ai_protocol = protocol;
	ai_list->ai_flags = flags;

	ai_list = ai_reverse(ai_list);

	*res = ai_list;
	return (0);
}
Exemple #19
0
/* Receive packet */
void
l2tp_ctrl_input(l2tpd *_this, int listener_index, struct sockaddr *peer,
    struct sockaddr *sock, void *nat_t_ctx, u_char *pkt, int pktlen)
{
	int i, len, offsiz, reqlen, is_ctrl;
	uint16_t mestype;
	struct l2tp_avp *avp, *avp0;
	l2tp_ctrl *ctrl;
	l2tp_call *call;
	char buf[L2TP_AVP_MAXSIZ], errmsg[256];
	time_t curr_time;
	u_char *pkt0;
	struct l2tp_header hdr;
	char hbuf[NI_MAXHOST + NI_MAXSERV + 16];

	ctrl = NULL;
	curr_time = get_monosec();
	pkt0 = pkt;

	L2TP_CTRL_ASSERT(peer->sa_family == sock->sa_family);
	L2TP_CTRL_ASSERT(peer->sa_family == AF_INET ||
	    peer->sa_family == AF_INET6)
    /*
     * Parse L2TP Header
     */
	memset(&hdr, 0, sizeof(hdr));
	if (pktlen < 2) {
		snprintf(errmsg, sizeof(errmsg), "a short packet.  "
		    "length=%d", pktlen);
		goto bad_packet;
	}
	memcpy(&hdr, pkt, 2);
	pkt += 2;
	if (hdr.ver != L2TP_HEADER_VERSION_RFC2661) {
		/* XXX: only RFC2661 is supported */
		snprintf(errmsg, sizeof(errmsg),
		    "Unsupported version at header = %d", hdr.ver);
		goto bad_packet;
	}
	is_ctrl = (hdr.t != 0)? 1 : 0;

	/* calc required length */
	reqlen = 6;		/* for Flags, Tunnel-Id, Session-Id field */
	if (hdr.l) reqlen += 2;	/* for Length field (opt) */
	if (hdr.s) reqlen += 4;	/* for Ns, Nr field (opt) */
	if (hdr.o) reqlen += 2;	/* for Offset Size field (opt) */
	if (reqlen > pktlen) {
		snprintf(errmsg, sizeof(errmsg),
		    "a short packet. length=%d", pktlen);
		goto bad_packet;
	}

	if (hdr.l != 0) {
		GETSHORT(hdr.length, pkt);
		if (hdr.length > pktlen) {
			snprintf(errmsg, sizeof(errmsg),
			    "Actual packet size is smaller than the length "
			    "field %d < %d", pktlen, hdr.length);
			goto bad_packet;
		}
		pktlen = hdr.length;	/* remove trailing trash */
	}
	GETSHORT(hdr.tunnel_id, pkt);
	GETSHORT(hdr.session_id, pkt);
	if (hdr.s != 0) {
		GETSHORT(hdr.ns, pkt);
		GETSHORT(hdr.nr, pkt);
	}
	if (hdr.o != 0) {
		GETSHORT(offsiz, pkt);
		if (pktlen < offsiz) {
			snprintf(errmsg, sizeof(errmsg),
			    "offset field is bigger than remaining packet "
			    "length %d > %d", offsiz, pktlen);
			goto bad_packet;
		}
		pkt += offsiz;
	}
	L2TP_CTRL_ASSERT(pkt - pkt0 == reqlen);
	pktlen -= (pkt - pkt0);	/* cut down the length of header */

	ctrl = NULL;
	memset(buf, 0, sizeof(buf));
	mestype = 0;
	avp = NULL;

	if (is_ctrl) {
		avp0 = (struct l2tp_avp *)buf;
		avp = avp_find_message_type_avp(avp0, pkt, pktlen);
		if (avp != NULL)
			mestype = avp->attr_value[0] << 8 | avp->attr_value[1];
	}
	ctrl = l2tpd_get_ctrl(_this, hdr.tunnel_id);

	if (ctrl == NULL) {
		/* new control */
		if (!is_ctrl) {
			snprintf(errmsg, sizeof(errmsg),
			    "bad data message: tunnelId=%d is not "
			    "found.", hdr.tunnel_id);
			goto bad_packet;
		}
		if (mestype != L2TP_AVP_MESSAGE_TYPE_SCCRQ) {
			snprintf(errmsg, sizeof(errmsg),
			    "bad control message: tunnelId=%d is not "
			    "found.  mestype=%s", hdr.tunnel_id,
			    avp_mes_type_string(mestype));
			goto bad_packet;
		}

		if ((ctrl = l2tp_ctrl_create()) == NULL) {
			l2tp_ctrl_log(ctrl, LOG_ERR,
			    "l2tp_ctrl_create() failed: %m");
			goto fail;
		}

		if (l2tp_ctrl_init(ctrl, _this, peer, sock, nat_t_ctx) != 0) {
			l2tp_ctrl_log(ctrl, LOG_ERR,
			    "l2tp_ctrl_start() failed: %m");
			goto fail;
		}

		ctrl->listener_index = listener_index;
		l2tp_ctrl_reload(ctrl);
	} else {
		/*
		 * treat as an error if src address and port is not
		 * match. (because it is potentially DoS attach)
		 */
		int notmatch = 0;

		if (ctrl->peer.ss_family != peer->sa_family)
			notmatch = 1;
		else if (peer->sa_family == AF_INET) {
			if (SIN(peer)->sin_addr.s_addr != 
			    SIN(&ctrl->peer)->sin_addr.s_addr ||
			    SIN(peer)->sin_port != SIN(&ctrl->peer)->sin_port)
				notmatch = 1;
		} else if (peer->sa_family == AF_INET6) {
			if (!IN6_ARE_ADDR_EQUAL(&(SIN6(peer)->sin6_addr),
				    &(SIN6(&ctrl->peer)->sin6_addr)) ||
			    SIN6(peer)->sin6_port !=
				    SIN6(&ctrl->peer)->sin6_port)
				notmatch = 1;
 		}
		if (notmatch) {
			snprintf(errmsg, sizeof(errmsg),
			    "tunnelId=%u is already assigned for %s",
			    hdr.tunnel_id, addrport_tostring(
				(struct sockaddr *)&ctrl->peer,
				ctrl->peer.ss_len, hbuf, sizeof(hbuf)));
			goto bad_packet;
		}
	}
	ctrl->last_rcv = curr_time;
	call = NULL;
	if (hdr.session_id != 0) {
		/* search l2tp_call by Session ID */
		/* linear search is enough for this purpose */
		len = slist_length(&ctrl->call_list);
		for (i = 0; i < len; i++) {
			call = slist_get(&ctrl->call_list, i);
			if (call->session_id == hdr.session_id)
				break;
			call = NULL;
		}
	}
	if (!is_ctrl) {
		int delayed = 0;

		/* L2TP data */
		if (ctrl->state != L2TP_CTRL_STATE_ESTABLISHED) {
			l2tp_ctrl_log(ctrl, LOG_WARNING,
			    "Received Data packet in '%s'",
			    l2tp_ctrl_state_string(ctrl));
			goto fail;
		}
		if (call == NULL) {
			l2tp_ctrl_log(ctrl, LOG_WARNING,
			    "Received a data packet but it has no call.  "
			    "session_id=%u",  hdr.session_id);
			goto fail;
		}
		L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2,
		    "call=%u RECV   ns=%u nr=%u snd_nxt=%u rcv_nxt=%u len=%d",
		    call->id, hdr.ns, hdr.nr, call->snd_nxt, call->rcv_nxt,
		    pktlen));
		if (call->state != L2TP_CALL_STATE_ESTABLISHED){
			l2tp_ctrl_log(ctrl, LOG_WARNING,
			    "Received a data packet but call is not "
			    "established");
			goto fail;
		}

		if (hdr.s != 0) {
			if (SEQ_LT(hdr.ns, call->rcv_nxt)) {
				if (SEQ_LT(hdr.ns,
				    call->rcv_nxt - L2TP_CALL_DELAY_LIMIT)) {
					/* sequence number seems to be delayed */
					/* XXX: need to log? */
					L2TP_CTRL_DBG((ctrl, LOG_DEBUG,
					    "receive a out of sequence "
					    "data packet: %u < %u.",
					    hdr.ns, call->rcv_nxt));
					return;
				}
				delayed = 1;
			} else {
				call->rcv_nxt = hdr.ns + 1;
			}
		}

		l2tp_call_ppp_input(call, pkt, pktlen, delayed);

		return;
	}
	if (hdr.s != 0) {
		L2TP_CTRL_DBG((ctrl, DEBUG_LEVEL_2,
		    "RECV %s ns=%u nr=%u snd_nxt=%u snd_una=%u rcv_nxt=%u "
		    "len=%d", (is_ctrl)? "C" : "", hdr.ns, hdr.nr,
		    ctrl->snd_nxt, ctrl->snd_una, ctrl->rcv_nxt, pktlen));

		if (pktlen <= 0)
			l2tp_ctrl_log(ctrl, LOG_INFO, "RecvZLB");

		if (SEQ_GT(hdr.nr, ctrl->snd_una)) {
			if (hdr.nr == ctrl->snd_nxt ||
			    SEQ_LT(hdr.nr, ctrl->snd_nxt))
				ctrl->snd_una = hdr.nr;
			else {
				l2tp_ctrl_log(ctrl, LOG_INFO,
				    "Received message has bad Nr field: "
				    "%u < %u.", hdr.ns, ctrl->snd_nxt);
				/* XXX Drop with ZLB? */
				goto fail;
			}
		}
		if (l2tp_ctrl_txwin_size(ctrl) <= 0) {
			/* no waiting ack */
			if (ctrl->hello_wait_ack != 0) {
				/*
				 * Reset Hello state, as an ack for the Hello
				 * is recived.
				 */
				ctrl->hello_wait_ack = 0;
				ctrl->hello_io_time = curr_time;
			}
			switch (ctrl->state) {
			case L2TP_CTRL_STATE_CLEANUP_WAIT:
				l2tp_ctrl_stop(ctrl, 0);
				return;
			}
		}
		if (hdr.ns != ctrl->rcv_nxt) {
			/* there are remaining packet */
			if (l2tp_ctrl_resend_una_packets(ctrl) <= 0) {
				/* resend or sent ZLB */
				l2tp_ctrl_send_ZLB(ctrl);
			}
#ifdef	L2TP_CTRL_DEBUG
			if (pktlen != 0) {	/* not ZLB */
				L2TP_CTRL_DBG((ctrl, LOG_DEBUG,
				    "receive out of sequence %u must be %u.  "
				    "mestype=%s", hdr.ns, ctrl->rcv_nxt,
				    avp_mes_type_string(mestype)));
			}
#endif
			return;
		}
		if (pktlen <= 0)
			return;		/* ZLB */

		if (l2tp_ctrl_txwin_is_full(ctrl)) {
			L2TP_CTRL_DBG((ctrl, LOG_DEBUG,
			    "Received message cannot be handled. "
			    "Transmission window is full."));
			l2tp_ctrl_send_ZLB(ctrl);
			return;
		}

		ctrl->rcv_nxt++;
		if (avp == NULL) {
			l2tpd_log(_this, LOG_WARNING,
			    "bad control message: no message-type AVP.");
			goto fail;
		}
	}

    /*
     * state machine (RFC2661 pp. 56-57)
     */
	switch (ctrl->state) {
	case L2TP_CTRL_STATE_IDLE:
		switch (mestype) {
		case L2TP_AVP_MESSAGE_TYPE_SCCRQ:
			if (l2tp_ctrl_recv_SCCRQ(ctrl, pkt, pktlen, _this,
			    peer) == 0) {
				/* acceptable */
				l2tp_ctrl_send_SCCRP(ctrl);
				ctrl->state = L2TP_CTRL_STATE_WAIT_CTL_CONN;
				return;
			}
			/*
			 * in case un-acceptable, it was already processed
			 * at l2tcp_ctrl_recv_SCCRQ
			 */
			return;
		case L2TP_AVP_MESSAGE_TYPE_SCCRP:
			/*
			 * RFC specifies that sent of StopCCN in the state,
			 * However as this implementation only support Passive
			 * open, this packet will not received.
			 */
			/* FALLTHROUGH */
		case L2TP_AVP_MESSAGE_TYPE_SCCCN:
		default:
			break;
		}
		goto fsm_fail;

	case L2TP_CTRL_STATE_WAIT_CTL_CONN:
	    /* Wait-Ctl-Conn */
		switch (mestype) {
		case L2TP_AVP_MESSAGE_TYPE_SCCCN:
			l2tp_ctrl_log(ctrl, LOG_INFO, "RecvSCCN");
			if (l2tp_ctrl_send_ZLB(ctrl) == 0) {
				ctrl->state = L2TP_CTRL_STATE_ESTABLISHED;
			}
			return;
		case L2TP_AVP_MESSAGE_TYPE_StopCCN:
			goto receive_stop_ccn;
		case L2TP_AVP_MESSAGE_TYPE_SCCRQ:
		case L2TP_AVP_MESSAGE_TYPE_SCCRP:
		default:
			break;
		}
		break;	/* fsm_fail */
	case L2TP_CTRL_STATE_ESTABLISHED:
	    /* Established */
		switch (mestype) {
		case L2TP_AVP_MESSAGE_TYPE_SCCCN:
		case L2TP_AVP_MESSAGE_TYPE_SCCRQ:
		case L2TP_AVP_MESSAGE_TYPE_SCCRP:
			break;
receive_stop_ccn:
		case L2TP_AVP_MESSAGE_TYPE_StopCCN:
			if (l2tp_ctrl_recv_StopCCN(ctrl, pkt, pktlen) == 0) {
				if (l2tp_ctrl_resend_una_packets(ctrl) <= 0)
					l2tp_ctrl_send_ZLB(ctrl);
				l2tp_ctrl_stop(ctrl, 0);
				return;
			}
			l2tp_ctrl_log(ctrl, LOG_ERR, "Received bad StopCCN");
			l2tp_ctrl_send_ZLB(ctrl);
			l2tp_ctrl_stop(ctrl, 0);
			return;

		case L2TP_AVP_MESSAGE_TYPE_HELLO:
			if (l2tp_ctrl_resend_una_packets(ctrl) <= 0)
				l2tp_ctrl_send_ZLB(ctrl);
			return;
		case L2TP_AVP_MESSAGE_TYPE_CDN:
		case L2TP_AVP_MESSAGE_TYPE_ICRP:
		case L2TP_AVP_MESSAGE_TYPE_ICCN:
			if (call == NULL) {
				l2tp_ctrl_log(ctrl, LOG_INFO,
				    "Unknown call message: %s",
				    avp_mes_type_string(mestype));
				goto fail;
			}
			/* FALLTHROUGH */
		case L2TP_AVP_MESSAGE_TYPE_ICRQ:
			l2tp_call_recv_packet(ctrl, call, mestype, pkt,
			    pktlen);
			return;
		default:
			break;
		}
		break;	/* fsm_fail */
	case L2TP_CTRL_STATE_CLEANUP_WAIT:
		if (mestype == L2TP_AVP_MESSAGE_TYPE_StopCCN) {
			/*
			 * We left ESTABLISHED state, but the peer sent StopCCN.
			 */
			goto receive_stop_ccn;
		}
		break;	/* fsm_fail */
	}

fsm_fail:
	/* state machine error */
	l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state",
	    avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl));
	l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_FSM_ERROR);

	return;
fail:
	if (ctrl != NULL && mestype != 0) {
		l2tp_ctrl_log(ctrl, LOG_WARNING, "Received %s in '%s' state",
		    avp_mes_type_string(mestype), l2tp_ctrl_state_string(ctrl));
		l2tp_ctrl_stop(ctrl, L2TP_STOP_CCN_RCODE_GENERAL_ERROR);
	}
	return;

bad_packet:
	l2tpd_log(_this, LOG_INFO, "Received from=%s: %s",
	    addrport_tostring(peer, peer->sa_len, hbuf, sizeof(hbuf)), errmsg);

	return;
}
Exemple #20
0
/** Delete the IPsec SA for disconnection */
static void
l2tp_ctrl_purge_ipsec_sa(l2tp_ctrl *_this)
{
	int is_natt, proto;
	struct sockaddr_storage peer, sock;
	hash_link *hl;
#ifdef USE_LIBSOCKUTIL
	struct in_ipsec_sa_cookie *ipsec_sa_cookie;
#endif
	l2tp_ctrl *anot;

	/*
	 * Search another tunnel that uses the same IPsec SA
	 * by lineer.
	 */
	for (hl = hash_first(_this->l2tpd->ctrl_map);
	    hl != NULL; hl = hash_next(_this->l2tpd->ctrl_map)) {
		anot = hl->item;
		if (anot == _this)
			continue;

		if (_this->peer.ss_family != anot->peer.ss_family)
			continue;
		if (_this->peer.ss_family == AF_INET) {
			if (SIN(&_this->peer)->sin_addr.s_addr !=
			    SIN(&anot->peer)->sin_addr.s_addr)
				continue;
		} else if (_this->peer.ss_family == AF_INET6) {
			if (!IN6_ARE_ADDR_EQUAL(
			    &(SIN6(&_this->peer)->sin6_addr),
			    &(SIN6(&anot->peer)->sin6_addr)))
				continue;
		}
#ifdef USE_LIBSOCKUTIL
		if (_this->sa_cookie != NULL && anot->sa_cookie != NULL) {
			/* Both tunnels belong the same NAT box.  */

			if (memcmp(_this->sa_cookie, anot->sa_cookie,
			    sizeof(struct in_ipsec_sa_cookie)) != 0)
				/* Different hosts behind the NAT box.  */
				continue;

			/* The SA is shared by another tunnels by one host. */
			return;	/* don't purge the sa */

		} else if (_this->sa_cookie != NULL || anot->sa_cookie != NULL)
			/* Only one is behind the NAT */
			continue;
#endif
		return;	/* don't purge the sa */
	}

#if defined(USE_LIBSOCKUTIL)  && defined(IP_IPSEC_SA_COOKIE)
	is_natt = (_this->sa_cookie != NULL)? 1 : 0;
#else
	is_natt = 0;
#endif
	proto = 0;
	memcpy(&peer, &_this->peer, _this->peer.ss_len);
	memcpy(&sock, &_this->sock, _this->sock.ss_len);
	if (!is_natt)
		SIN(&peer)->sin_port = SIN(&sock)->sin_port = 0;
#if defined(USE_LIBSOCKUTIL)  && defined(IP_IPSEC_SA_COOKIE)
	else {
		ipsec_sa_cookie = _this->sa_cookie;
		SIN(&peer)->sin_port = ipsec_sa_cookie->remote_port;
		SIN(&sock)->sin_port = ipsec_sa_cookie->local_port;
#if 1
		/*
		 * XXX: As RFC 2367, protocol sould be specified if the port
		 * XXX: number is non-zero.
		 */
		proto = 0;
#else
		proto = IPPROTO_UDP;
#endif
	}
#endif
	if (ipsec_util_purge_transport_sa((struct sockaddr *)&peer,
	    (struct sockaddr *)&sock, proto, IPSEC_UTIL_DIRECTION_BOTH) != 0)
		l2tp_ctrl_log(_this, LOG_NOTICE, "failed to purge IPSec SA");
}
Exemple #21
0
void sin_set_port(struct sockaddr_storage *ss, in_port_t port) {
	if (ss->ss_family == AF_INET6)
		SIN6(ss)->sin6_port = port;

	SIN4(ss)->sin_port = port;
}
Exemple #22
0
char *
get_next_msg(char *buf, char *lim, size_t *lenp)
{
	struct rt_msghdr *rtm;
	struct ifa_msghdr *ifam;
	struct sockaddr *sa, *dst, *ifa, *rti_info[RTAX_MAX];

	*lenp = 0;
	for (rtm = (struct rt_msghdr *)buf;
	     rtm < (struct rt_msghdr *)lim;
	     rtm = (struct rt_msghdr *)((char *)rtm + rtm->rtm_msglen)) {
		/* just for safety */
		if (!rtm->rtm_msglen) {
			log_warnx("rtm_msglen is 0 (buf=%p lim=%p rtm=%p)",
			    buf, lim, rtm);
			break;
		}
		if (rtm->rtm_version != RTM_VERSION)
			continue;

		switch (rtm->rtm_type) {
		case RTM_ADD:
		case RTM_DELETE:
			if (rtm->rtm_tableid != 0)
				continue;

			/* address related checks */
			sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen);
			get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
			if ((dst = rti_info[RTAX_DST]) == NULL ||
			    dst->sa_family != AF_INET6)
				continue;

			if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
			    IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
				continue;

			if (rti_info[RTAX_NETMASK] == NULL)
				continue;

			/* found */
			*lenp = rtm->rtm_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		case RTM_NEWADDR:
		case RTM_DELADDR:
			ifam = (struct ifa_msghdr *)rtm;

			/* address related checks */
			sa = (struct sockaddr *)((char *)rtm + rtm->rtm_hdrlen);
			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
			if ((ifa = rti_info[RTAX_IFA]) == NULL ||
			    (ifa->sa_family != AF_INET &&
			     ifa->sa_family != AF_INET6))
				continue;

			if (ifa->sa_family == AF_INET6 &&
			    (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
			     IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
				continue;

			/* found */
			*lenp = rtm->rtm_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		case RTM_IFINFO:
			/* found */
			*lenp = rtm->rtm_msglen;
			return (char *)rtm;
			/* NOTREACHED */
		}
	}

	return (char *)rtm;
}
Exemple #23
0
/*%
 * Get a list of IP addresses and port numbers for host hostname and
 * service servname.
 */
int
getaddrinfo(const char *hostname, const char *servname,
	    const struct addrinfo *hints, struct addrinfo **res)
{
	struct servent *sp;
	const char *proto;
	int family, socktype, flags, protocol;
	struct addrinfo *ai, *ai_list;
	int err = 0;
	int port, i;
	int (*net_order[FOUND_MAX+1])(const char *, int, struct addrinfo **,
				      int, int);

	if (hostname == NULL && servname == NULL)
		return (EAI_NONAME);

	proto = NULL;
	if (hints != NULL) {
		if ((hints->ai_flags & ~(ISC_AI_MASK)) != 0)
			return (EAI_BADFLAGS);
		if (hints->ai_addrlen || hints->ai_canonname ||
		    hints->ai_addr || hints->ai_next) {
			errno = EINVAL;
			return (EAI_SYSTEM);
		}
		family = hints->ai_family;
		socktype = hints->ai_socktype;
		protocol = hints->ai_protocol;
		flags = hints->ai_flags;
		switch (family) {
		case AF_UNSPEC:
			switch (hints->ai_socktype) {
			case SOCK_STREAM:
				proto = "tcp";
				break;
			case SOCK_DGRAM:
				proto = "udp";
				break;
			}
			break;
		case AF_INET:
		case AF_INET6:
			switch (hints->ai_socktype) {
			case 0:
				break;
			case SOCK_STREAM:
				proto = "tcp";
				break;
			case SOCK_DGRAM:
				proto = "udp";
				break;
			case SOCK_RAW:
				break;
			default:
				return (EAI_SOCKTYPE);
			}
			break;
#ifdef	AF_LOCAL
		case AF_LOCAL:
			switch (hints->ai_socktype) {
			case 0:
				break;
			case SOCK_STREAM:
				break;
			case SOCK_DGRAM:
				break;
			default:
				return (EAI_SOCKTYPE);
			}
			break;
#endif
		default:
			return (EAI_FAMILY);
		}
	} else {
		protocol = 0;
		family = 0;
		socktype = 0;
		flags = 0;
	}

#ifdef	AF_LOCAL
	/*!
	 * First, deal with AF_LOCAL.  If the family was not set,
	 * then assume AF_LOCAL if the first character of the
	 * hostname/servname is '/'.
	 */

	if (hostname != NULL &&
	    (family == AF_LOCAL || (family == 0 && *hostname == '/')))
		return (get_local(hostname, socktype, res));

	if (servname != NULL &&
	    (family == AF_LOCAL || (family == 0 && *servname == '/')))
		return (get_local(servname, socktype, res));
#endif

	/*
	 * Ok, only AF_INET and AF_INET6 left.
	 */
	ai_list = NULL;

	/*
	 * First, look up the service name (port) if it was
	 * requested.  If the socket type wasn't specified, then
	 * try and figure it out.
	 */
	if (servname != NULL) {
		char *e;

		port = strtol(servname, &e, 10);
		if (*e == '\0') {
			if (socktype == 0)
				return (EAI_SOCKTYPE);
			if (port < 0 || port > 65535)
				return (EAI_SERVICE);
			port = htons((unsigned short) port);
		} else {
			sp = getservbyname(servname, proto);
			if (sp == NULL)
				return (EAI_SERVICE);
			port = sp->s_port;
			if (socktype == 0) {
				if (strcmp(sp->s_proto, "tcp") == 0)
					socktype = SOCK_STREAM;
				else if (strcmp(sp->s_proto, "udp") == 0)
					socktype = SOCK_DGRAM;
			}
		}
	} else
		port = 0;

	/*
	 * Next, deal with just a service name, and no hostname.
	 * (we verified that one of them was non-null up above).
	 */
	if (hostname == NULL && (flags & AI_PASSIVE) != 0) {
		if (family == AF_INET || family == 0) {
			ai = ai_alloc(AF_INET, sizeof(struct sockaddr_in));
			if (ai == NULL)
				return (EAI_MEMORY);
			ai->ai_socktype = socktype;
			ai->ai_protocol = protocol;
			SIN(ai->ai_addr)->sin_port = port;
			ai->ai_next = ai_list;
			ai_list = ai;
		}

		if (family == AF_INET6 || family == 0) {
			ai = ai_alloc(AF_INET6, sizeof(struct sockaddr_in6));
			if (ai == NULL) {
				_freeaddrinfo(ai_list);
				return (EAI_MEMORY);
			}
			ai->ai_socktype = socktype;
			ai->ai_protocol = protocol;
			SIN6(ai->ai_addr)->sin6_port = port;
			ai->ai_next = ai_list;
			ai_list = ai;
		}

		*res = ai_list;
		return (0);
	}

	/*
	 * If the family isn't specified or AI_NUMERICHOST specified, check
	 * first to see if it is a numeric address.
	 * Though the gethostbyname2() routine will recognize numeric addresses,
	 * it will only recognize the format that it is being called for.  Thus,
	 * a numeric AF_INET address will be treated by the AF_INET6 call as
	 * a domain name, and vice versa.  Checking for both numerics here
	 * avoids that.
	 */
	if (hostname != NULL &&
	    (family == 0 || (flags & AI_NUMERICHOST) != 0)) {
		char abuf[sizeof(struct in6_addr)];
		char nbuf[NI_MAXHOST];
		int addrsize, addroff;
#ifdef IRS_HAVE_SIN6_SCOPE_ID
		char *p, *ep;
		char ntmp[NI_MAXHOST];
		isc_uint32_t scopeid;
#endif

#ifdef IRS_HAVE_SIN6_SCOPE_ID
		/*
		 * Scope identifier portion.
		 */
		ntmp[0] = '\0';
		if (strchr(hostname, '%') != NULL) {
			strncpy(ntmp, hostname, sizeof(ntmp) - 1);
			ntmp[sizeof(ntmp) - 1] = '\0';
			p = strchr(ntmp, '%');
			ep = NULL;

			/*
			 * Vendors may want to support non-numeric
			 * scopeid around here.
			 */

			if (p != NULL)
				scopeid = (isc_uint32_t)strtoul(p + 1,
								&ep, 10);
			if (p != NULL && ep != NULL && ep[0] == '\0')
				*p = '\0';
			else {
				ntmp[0] = '\0';
				scopeid = 0;
			}
		} else
			scopeid = 0;
#endif

		if (inet_pton(AF_INET, hostname, (struct in_addr *)abuf)
		    == 1) {
			if (family == AF_INET6) {
				/*
				 * Convert to a V4 mapped address.
				 */
				struct in6_addr *a6 = (struct in6_addr *)abuf;
				memmove(&a6->s6_addr[12], &a6->s6_addr[0], 4);
				memset(&a6->s6_addr[10], 0xff, 2);
				memset(&a6->s6_addr[0], 0, 10);
				goto inet6_addr;
			}
			addrsize = sizeof(struct in_addr);
			addroff = (char *)(&SIN(0)->sin_addr) - (char *)0;
			family = AF_INET;
			goto common;
#ifdef IRS_HAVE_SIN6_SCOPE_ID
		} else if (ntmp[0] != '\0' &&
			   inet_pton(AF_INET6, ntmp, abuf) == 1) {
			if (family && family != AF_INET6)
				return (EAI_NONAME);
			addrsize = sizeof(struct in6_addr);
			addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
			family = AF_INET6;
			goto common;
#endif
		} else if (inet_pton(AF_INET6, hostname, abuf) == 1) {
			if (family != 0 && family != AF_INET6)
				return (EAI_NONAME);
		inet6_addr:
			addrsize = sizeof(struct in6_addr);
			addroff = (char *)(&SIN6(0)->sin6_addr) - (char *)0;
			family = AF_INET6;

		common:
			ai = ai_alloc(family,
				      ((family == AF_INET6) ?
				       sizeof(struct sockaddr_in6) :
				       sizeof(struct sockaddr_in)));
			if (ai == NULL)
				return (EAI_MEMORY);
			ai_list = ai;
			ai->ai_socktype = socktype;
			SIN(ai->ai_addr)->sin_port = port;
			memmove((char *)ai->ai_addr + addroff, abuf, addrsize);
			if ((flags & AI_CANONNAME) != 0) {
#ifdef IRS_HAVE_SIN6_SCOPE_ID
				if (ai->ai_family == AF_INET6)
					SIN6(ai->ai_addr)->sin6_scope_id =
						scopeid;
#endif
				if (getnameinfo(ai->ai_addr,
						(socklen_t)ai->ai_addrlen,
						nbuf, sizeof(nbuf), NULL, 0,
						NI_NUMERICHOST) == 0) {
					ai->ai_canonname = strdup(nbuf);
					if (ai->ai_canonname == NULL) {
						_freeaddrinfo(ai);
						return (EAI_MEMORY);
					}
				} else {
					/* XXX raise error? */
					ai->ai_canonname = NULL;
				}
			}
			goto done;
		} else if ((flags & AI_NUMERICHOST) != 0) {
			return (EAI_NONAME);
		}
	}

	if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
		set_order(family, net_order);
		for (i = 0; i < FOUND_MAX; i++) {
			if (net_order[i] == NULL)
				break;
			err = (net_order[i])(hostname, flags, &ai_list,
					     socktype, port);
			if (err != 0) {
				if (ai_list != NULL) {
					_freeaddrinfo(ai_list);
					ai_list = NULL;
				}
				break;
			}
		}
	} else
		err = resolve_name(family, hostname, flags, &ai_list,
				   socktype, port);

	if (ai_list == NULL) {
		if (err == 0)
			err = EAI_NONAME;
		return (err);
	}

done:
	ai_list = ai_reverse(ai_list);

	*res = ai_list;
	return (0);
}
Exemple #24
0
static int
add_ipv6(const char *hostname, int flags, struct addrinfo **aip,
	 int socktype, int port)
{
	struct addrinfo *ai;
	lwres_context_t *lwrctx = NULL;
	lwres_gabnresponse_t *by = NULL;
	lwres_addr_t *addr;
	lwres_result_t lwres;
	int result = 0;

	lwres = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0);
	if (lwres != LWRES_R_SUCCESS)
		ERR(EAI_FAIL);
	(void) lwres_conf_parse(lwrctx, lwres_resolv_conf);

	if (hostname == NULL && (flags & AI_PASSIVE) == 0) {
		ai = ai_clone(*aip, AF_INET6);
		if (ai == NULL) {
			lwres_freeaddrinfo(*aip);
			ERR(EAI_MEMORY);
		}

		*aip = ai;
		ai->ai_socktype = socktype;
		SIN6(ai->ai_addr)->sin6_port = port;
		memcpy(&SIN6(ai->ai_addr)->sin6_addr, v6_loop, 16);
	} else {
		lwres = lwres_getaddrsbyname(lwrctx, hostname,
					     LWRES_ADDRTYPE_V6, &by);
		if (lwres != LWRES_R_SUCCESS) {
			if (lwres == LWRES_R_NOTFOUND)
				goto cleanup;
			else
				ERR(EAI_FAIL);
		}
		addr = LWRES_LIST_HEAD(by->addrs);
		while (addr != NULL) {
			ai = ai_clone(*aip, AF_INET6);
			if (ai == NULL) {
				lwres_freeaddrinfo(*aip);
				ERR(EAI_MEMORY);
			}
			*aip = ai;
			ai->ai_socktype = socktype;
			SIN6(ai->ai_addr)->sin6_port = port;
			memcpy(&SIN6(ai->ai_addr)->sin6_addr,
			       addr->address, 16);
			if (flags & AI_CANONNAME) {
				ai->ai_canonname = strdup(by->realname);
				if (ai->ai_canonname == NULL)
					ERR(EAI_MEMORY);
			}
			addr = LWRES_LIST_NEXT(addr, link);
		}
	}
 cleanup:
	if (by != NULL)
		lwres_gabnresponse_free(lwrctx, &by);
	if (lwrctx != NULL) {
		lwres_conf_clear(lwrctx);
		lwres_context_destroy(&lwrctx);
	}
	return (result);
}