Beispiel #1
0
/**
 * IpToString
 *
 * Converts a sockaddr struct into a string.
 *
 * @param Address the address
 */
const char *IpToString(sockaddr *Address) {
	static char Buffer[256];

#ifdef _WIN32
	DWORD BufferLength = sizeof(Buffer);

	if (WSAAddressToString(Address, SOCKADDR_LEN(Address->sa_family), NULL, Buffer, &BufferLength) != 0) {
		return NULL;
	}
#else
	void *IpAddress;

	if (Address->sa_family == AF_INET) {
		IpAddress = &(((sockaddr_in *)Address)->sin_addr);
	} else {
		IpAddress = &(((sockaddr_in6 *)Address)->sin6_addr);
	}

	if (inet_ntop(Address->sa_family, IpAddress, Buffer, sizeof(Buffer)) == NULL) {
		return NULL;
	}
#endif

	return Buffer;
}
Beispiel #2
0
bool StringToIp(const char *IP, int Family, sockaddr *SockAddr, socklen_t Length) {
	memset(SockAddr, 0, Length);

#ifdef _WIN32
	socklen_t *LengthPtr = &Length;

	if (WSAStringToAddress(const_cast<char *>(IP), Family, NULL, SockAddr, LengthPtr) != 0) {
		return false;
	}
#else
	if (Length < SOCKADDR_LEN(Family)) {
		return false;
	}

	if (inet_pton(Family, IP, SockAddr) <= 0) {
		return false;
	}
#endif

	return true;
}
Beispiel #3
0
/**
 * CreateListener
 *
 * Creates a new listening socket.
 *
 * @param Port the port this socket should listen on
 * @param BindIp the IP address this socket should be bound to
 * @param Family address family (i.e. IPv4 or IPv6)
 */
SOCKET CreateListener(unsigned int Port, const char *BindIp, int Family) {
	sockaddr *saddr;
	sockaddr_in sin;
#ifdef HAVE_IPV6
	sockaddr_in6 sin6;
#endif /* HAVE_IPV6 */
	const int optTrue = 1;
	bool Bound = false;
	SOCKET Listener;
	hostent *hent;

	Listener = socket(Family, SOCK_STREAM, IPPROTO_TCP);

	if (Listener == INVALID_SOCKET) {
		return INVALID_SOCKET;
	}

#ifndef _WIN32
	setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, (char *)&optTrue, sizeof(optTrue));
#endif

#ifdef HAVE_IPV6
	if (Family == AF_INET) {
#endif /* HAVE_IPV6 */
		sin.sin_family = AF_INET;
		sin.sin_port = htons(Port);

		saddr = (sockaddr *)&sin;
#ifdef HAVE_IPV6 /* HAVE_IPV6 */
	} else if (Family == AF_INET6) {
		memset(&sin6, 0, sizeof(sin6));
		sin6.sin6_family = AF_INET6;
		sin6.sin6_port = htons(Port);

		saddr = (sockaddr *)&sin6;

#if !defined(_WIN32) && defined(IPV6_V6ONLY)
		setsockopt(Listener, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&optTrue, sizeof(optTrue));
#endif
	} else {
		closesocket(Listener);

		return INVALID_SOCKET;
	}
#endif /* HAVE_IPV6 */

	if (BindIp) {
		hent = gethostbyname(BindIp);

		if (hent) {
#ifdef HAVE_IPV6
			if (Family == AF_INET) {
#endif /* HAVE_IPV6 */
				sin.sin_addr.s_addr = ((in_addr*)hent->h_addr_list[0])->s_addr;
#ifdef HAVE_IPV6
			} else {
				memcpy(&(sin6.sin6_addr.s6_addr), &(((in6_addr*)hent->h_addr_list[0])->s6_addr), sizeof(in6_addr));
			}
#endif /* HAVE_IPV6 */

			Bound = true;
		}
	}

	if (!Bound) {
#ifdef HAVE_IPV6
		if (Family == AF_INET) {
#endif /* HAVE_IPV6 */
			sin.sin_addr.s_addr = htonl(INADDR_ANY);
#ifdef HAVE_IPV6
		} else {
			const struct in6_addr v6any = IN6ADDR_ANY_INIT;

			memcpy(&(sin6.sin6_addr.s6_addr), &v6any, sizeof(in6_addr));
		}
#endif /* HAVE_IPV6 */
	}

	if (bind(Listener, saddr, SOCKADDR_LEN(Family)) != 0) {
		closesocket(Listener);

		return INVALID_SOCKET;
	}

	if (listen(Listener, SOMAXCONN) != 0) {
		closesocket(Listener);

		return INVALID_SOCKET;
	}

	return Listener;
}
Beispiel #4
0
/**
 * SocketAndConnect
 *
 * Creates a socket and connects to the specified host/port. You should use
 * SocketAndConnectResolved instead wherever possible as this function uses
 * blocking DNS requests.
 *
 * @param Host the host
 * @param Port the port
 * @param BindIp the ip address/hostname which should be used for binding the socket
 */
SOCKET SocketAndConnect(const char *Host, unsigned int Port, const char *BindIp) {
	unsigned long lTrue = 1;
	sockaddr_in sin, sloc;
	SOCKET Socket;
	hostent *hent;
	unsigned long addr;
	int code;

	if (Host == NULL || Port == 0) {
		return INVALID_SOCKET;
	}

	Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (Socket == INVALID_SOCKET) {
		return INVALID_SOCKET;
	}

	ioctlsocket(Socket, FIONBIO, &lTrue);

	if (BindIp && *BindIp) {
		sloc.sin_family = AF_INET;
		sloc.sin_port = 0;

		hent = gethostbyname(BindIp);

		if (hent) {
			in_addr *peer = (in_addr *)hent->h_addr_list[0];

			sloc.sin_addr.s_addr = peer->s_addr;
		} else {
			addr = inet_addr(BindIp);

			sloc.sin_addr.s_addr = addr;
		}

		bind(Socket, (sockaddr *)&sloc, sizeof(sloc));
	}

	sin.sin_family = AF_INET;
	sin.sin_port = htons(Port);

	hent = gethostbyname(Host);

	if (hent) {
		in_addr *peer = (in_addr *)hent->h_addr_list[0];

		sin.sin_addr.s_addr = peer->s_addr;
	} else {
		addr = inet_addr(Host);

		sin.sin_addr.s_addr = addr;
	}

	code = connect(Socket, (const sockaddr *)&sin, sizeof(sin));

#ifdef _WIN32
	if (code != 0 && errno != WSAEWOULDBLOCK) {
#else
	if (code != 0 && errno != EINPROGRESS) {
#endif
		closesocket(Socket);

		return INVALID_SOCKET;
	}

	return Socket;
}

/**
 * SocketAndConnectResolved
 *
 * Creates a socket and connects to the specified host/port. 
 *
 * @param Host the host's ip address
 * @param BindIp the ip address which should be used for binding the socket
 */
SOCKET SocketAndConnectResolved(const sockaddr *Host, const sockaddr *BindIp) {
	unsigned long lTrue = 1;
	int Code, Size;

	SOCKET Socket = socket(Host->sa_family, SOCK_STREAM, IPPROTO_TCP);

	if (Socket == INVALID_SOCKET) {
		return INVALID_SOCKET;
	}

	ioctlsocket(Socket, FIONBIO, &lTrue);

	if (BindIp != NULL) {
		bind(Socket, (sockaddr *)BindIp, SOCKADDR_LEN(BindIp->sa_family));
	}

	Size = SOCKADDR_LEN(Host->sa_family);

	Code = connect(Socket, Host, Size);

#ifdef _WIN32
	if (Code != 0 && WSAGetLastError() != WSAEWOULDBLOCK) {
#else
	if (Code != 0 && errno != EINPROGRESS) {
#endif
		closesocket(Socket);

		return INVALID_SOCKET;
	}

	return Socket;
}

/**
 * NickFromHostname
 *
 * Given a complete hostmask (nick!ident\@host) this function returns a copy
 * of the nickname. The result must be passed to free() when it is no longer used.
 *
 * @param Hostmask the hostmask
 */
char *NickFromHostmask(const char *Hostmask) {
	char *Copy;
	const char *ExclamationMark;

	ExclamationMark = strchr(Hostmask, '!');

	if (ExclamationMark == NULL) {
		return NULL;
	}

	Copy = strdup(Hostmask);

	if (AllocFailed(Copy)) {
		return NULL;
	}

	Copy[ExclamationMark - Hostmask] = '\0';

	return Copy;
}
Beispiel #5
0
/* get local address against the destination. */
struct sockaddr *
getlocaladdr(struct sockaddr *remote, struct sockaddr *hint, int lport)
{
	struct sockaddr *local;
	socklen_t local_len = sizeof(struct sockaddr_storage);
	int s;			/* for dummy connection */
	extern struct rcf_interface *rcf_interface_head;

	if (hint && hint->sa_family == remote->sa_family) {
		local = rcs_sadup(hint);
		goto got;
	}

	/* allocate buffer */
	if ((local = racoon_calloc(1, local_len)) == NULL) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "failed to get address buffer.\n");
		goto err;
	}

	/* get real interface received packet */
	if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "socket (%s)\n", strerror(errno));
		goto err;
	}
	if ((rcf_interface_head->application_bypass != RCT_BOOL_OFF) &&
	    (setsockopt_bypass(s, remote->sa_family) < 0)) {
		close(s);
		goto err;
	}
	if (connect(s, remote, SOCKADDR_LEN(remote)) < 0) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "connect (%s)\n", strerror(errno));
		close(s);
		goto err;
	}

	if (getsockname(s, local, &local_len) < 0) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "getsockname (%s)\n", strerror(errno));
		close(s);
		goto err;
	}

	close(s);

    got:
	/* specify local port */
	local->sa_family = remote->sa_family;
	switch (remote->sa_family) {
	case AF_INET:
		((struct sockaddr_in *)local)->sin_port = htons(lport);
		break;
#ifdef INET6
	case AF_INET6:
		((struct sockaddr_in6 *)local)->sin6_port = htons(lport);
		break;
#endif
	default:
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "getlocaladdr: unexpected address family (%d)\n",
		     remote->sa_family);
		goto err;
	}

	return local;

      err:
	if (local != NULL)
		racoon_free(local);
	return NULL;
}
Beispiel #6
0
/* send packet, with fixing src/dst address pair. */
int
sendfromto(int s, const void *buf, size_t buflen, 
	   struct sockaddr *src, struct sockaddr *dst, int cnt)
{
	struct sockaddr_storage ss;
	socklen_t sslen;
	int len = 0, i;
	extern struct rcf_interface *rcf_interface_head;

	if (cnt <= 0) {
		TRACE((PLOGLOC, "cnt: %d\n", cnt));
		return 0;
	}

	if (src->sa_family != dst->sa_family) {
		plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n");
		return -1;
	}

	memset(&ss, 0, sizeof(ss));
	sslen = sizeof(ss);
	if (getsockname(s, (struct sockaddr *)&ss, &sslen) < 0) {
		plog(PLOG_INTERR, PLOGLOC, NULL,
		     "getsockname (%s)\n", strerror(errno));
		return -1;
	}

	plog(PLOG_DEBUG, PLOGLOC, NULL,
	     "sockname %s\n", rcs_sa2str((struct sockaddr *)&ss));
	plog(PLOG_DEBUG, PLOGLOC, NULL,
	     "send packet from %s\n", rcs_sa2str(src));
	plog(PLOG_DEBUG, PLOGLOC, NULL, "send packet to %s\n", rcs_sa2str(dst));

	if (src->sa_family != SOCKADDR_FAMILY(&ss)) {
		plog(PLOG_INTERR, PLOGLOC, NULL, "address family mismatch\n");
		return -1;
	}

	switch (src->sa_family) {
#if defined(INET6) && defined(ADVAPI) && !defined(IPV6_INRIA_VERSION)
	case AF_INET6:
		{
			struct msghdr m;
			struct cmsghdr *cm;
			struct iovec iov[2];
			unsigned char cmsgbuf[256];
			struct in6_pktinfo *pi;
			int ifindex;
			struct sockaddr_in6 src6, dst6;

			memcpy(&src6, src, sizeof(src6));
			memcpy(&dst6, dst, sizeof(dst6));

			/* XXX take care of other cases, such as site-local */
			ifindex = 0;
			if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr)
			    || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) {
				ifindex = src6.sin6_scope_id;	/*??? */
			}

			/* XXX some sanity check on dst6.sin6_scope_id */

			/* flowinfo for IKE?  mmm, maybe useful but for now make it 0 */
			src6.sin6_flowinfo = dst6.sin6_flowinfo = 0;

			memset(&m, 0, sizeof(m));
			m.msg_name = (caddr_t)&dst6;
			m.msg_namelen = sizeof(dst6);
			iov[0].iov_base = (char *)buf;
			iov[0].iov_len = buflen;
			m.msg_iov = iov;
			m.msg_iovlen = 1;

			memset(cmsgbuf, 0, sizeof(cmsgbuf));
			cm = (struct cmsghdr *)cmsgbuf;
			m.msg_control = (caddr_t)cm;
			m.msg_controllen =
				CMSG_SPACE(sizeof(struct in6_pktinfo));

			cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
			cm->cmsg_level = IPPROTO_IPV6;
			cm->cmsg_type = IPV6_PKTINFO;
			pi = (struct in6_pktinfo *)CMSG_DATA(cm);
			memcpy(&pi->ipi6_addr, &src6.sin6_addr,
			       sizeof(src6.sin6_addr));
			pi->ipi6_ifindex = ifindex;

			plog(PLOG_DEBUG, PLOGLOC, NULL,
			     "src6 %s %d\n",
			     rcs_sa2str((struct sockaddr *)&src6),
			     src6.sin6_scope_id);
			plog(PLOG_DEBUG, PLOGLOC, NULL,
			     "dst6 %s %d\n",
			     rcs_sa2str((struct sockaddr *)&dst6),
			     dst6.sin6_scope_id);

			for (i = 0; i < cnt; i++) {
				len = sendmsg(s, &m, 0 /*MSG_DONTROUTE */ );
				if (len < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "sendmsg (%s)\n", strerror(errno));
					return -1;
				}
				plog(PLOG_DEBUG, PLOGLOC, NULL,
				     "%d times of %d bytes message will be sent "
				     "to %s\n", i + 1, len, rcs_sa2str(dst));
			}
			plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen);

			return len;
		}
#endif
	default:
		{
			int needclose = 0;
			int sendsock;

			if (rcs_cmpsa((struct sockaddr *)&ss, src) == 0) {
				sendsock = s;
				needclose = 0;
			} else {
				int yes = 1;
				/*
				 * Use newly opened socket for sending packets.
				 * NOTE: this is unsafe, because if the peer is quick enough
				 * the packet from the peer may be queued into sendsock.
				 * Better approach is to prepare bind'ed udp sockets for
				 * each of the interface addresses.
				 */
				sendsock =
					socket(src->sa_family, SOCK_DGRAM, 0);
				if (sendsock < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "socket (%s)\n", strerror(errno));
					return -1;
				}
#ifdef SO_REUSEPORT
				if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEPORT,
				     (void *)&yes, sizeof(yes)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "setsockopt (%s)\n",
					     strerror(errno));
					close(sendsock);
					return -1;
				}
#else
#ifdef SO_REUSEADDR
				if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEADDR,
				     (void *)&yes, sizeof(yes)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "setsockopt (%s)\n",
					     strerror(errno));
					close(sendsock);
					return -1;
				}
#else
#error
#endif
#endif

#ifdef IPV6_USE_MIN_MTU
				if (src->sa_family == AF_INET6 &&
				    setsockopt(sendsock, IPPROTO_IPV6,
					       IPV6_USE_MIN_MTU, (void *)&yes,
					       sizeof(yes)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "setsockopt (%s)\n",
					     strerror(errno));
					close(sendsock);
					return -1;
				}
#endif
				if (rcf_interface_head->application_bypass
				    != RCT_BOOL_OFF &&
				    setsockopt_bypass(sendsock, src->sa_family)
				    < 0) {
					close(sendsock);
					return -1;
				}

				if (bind
				    (sendsock, (struct sockaddr *)src,
				     SOCKADDR_LEN(src)) < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "bind 1 (%s)\n", strerror(errno));
					close(sendsock);
					return -1;
				}
				needclose = 1;
			}

			for (i = 0; i < cnt; i++) {
#ifdef DEBUG
				extern uint32_t debug_send;
				static int send_count = 0;

				if (debug_send & (1 << (send_count++ % 32))) {
					/* simulate a network packet drop */
					TRACE((PLOGLOC, "debug_send %d drop\n", send_count));
					len = buflen;
				} else
#endif
					len = sendto(sendsock, buf, buflen, 0,
						     dst, SOCKADDR_LEN(dst));
				if (len < 0) {
					plog(PLOG_INTERR, PLOGLOC, NULL,
					     "sendto (%s)\n", strerror(errno));
					if (needclose)
						close(sendsock);
					return len;
				}
				plog(PLOG_DEBUG, PLOGLOC, NULL,
				     "%d times of %d bytes message will be sent "
				     "to %s\n", i + 1, len, rcs_sa2str(dst));
			}
			plogdump(PLOG_DEBUG, PLOGLOC, 0, (char *)buf, buflen);

			if (needclose)
				close(sendsock);

			return len;
		}
	}
}