Example #1
0
File: nb_dns.c Project: bro/bro
struct nb_dns_info *
nb_dns_init2(char *errstr, struct sockaddr* sa)
{
	register struct nb_dns_info *nd;

	nd = (struct nb_dns_info *)malloc(sizeof(*nd));
	if (nd == NULL) {
		snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_init: malloc(): %s",
		    my_strerror(errno));
		return (NULL);
	}
	memset(nd, 0, sizeof(*nd));
	nd->s = -1;

	if ( sa->sa_family == AF_INET )
		{
		memcpy(&nd->server, sa, sizeof(struct sockaddr_in));
		((struct sockaddr_in*)&nd->server)->sin_port = htons(53);
		}
	else
		{
		memcpy(&nd->server, sa, sizeof(struct sockaddr_in6));
		((struct sockaddr_in6*)&nd->server)->sin6_port = htons(53);
		}

	nd->s = socket(nd->server.ss_family, SOCK_DGRAM, 0);

	if ( nd->s < 0 )
		{
		snprintf(errstr, NB_DNS_ERRSIZE, "socket(): %s",
		         my_strerror(errno));
		free(nd);
		return (NULL);
		}

	if ( connect(nd->s, (struct sockaddr *)&nd->server,
	             nd->server.ss_family == AF_INET ?
	                       sizeof(struct sockaddr_in) :
	                       sizeof(struct sockaddr_in6)) < 0 )
		{
		char s[INET6_ADDRSTRLEN];
		sa_ntop((struct sockaddr*)&nd->server, s, INET6_ADDRSTRLEN);
		snprintf(errstr, NB_DNS_ERRSIZE, "connect(%s): %s", s,
		         my_strerror(errno));
		close(nd->s);
		free(nd);
		return (NULL);
		}

	return (nd);
}
Example #2
0
/**
 * Create and listen on a UDP Socket
 *
 * @param usp   Pointer to returned UDP Socket
 * @param local Local network address
 * @param rh    Receive handler
 * @param arg   Handler argument
 *
 * @return 0 if success, otherwise errorcode
 */
int udp_listen(struct udp_sock **usp, const struct sa *local,
	       udp_recv_h *rh, void *arg)
{
	struct addrinfo hints, *res = NULL, *r;
	struct udp_sock *us = NULL;
	char addr[NET_ADDRSTRLEN];
	char serv[6] = "0";
	int af, error, err = 0;

	if (!usp)
		return EINVAL;

	us = mem_zalloc(sizeof(*us), udp_destructor);
	if (!us)
		return ENOMEM;

	list_init(&us->helpers);

	us->fd  = -1;
	us->fd6 = -1;

	if (local) {
		af = sa_af(local);
		err = sa_ntop(local, addr, sizeof(addr));
		(void)re_snprintf(serv, sizeof(serv), "%u", sa_port(local));
		if (err)
			goto out;
	}
	else {
#ifdef HAVE_INET6
		af = AF_UNSPEC;
#else
		af = AF_INET;
#endif
	}

	memset(&hints, 0, sizeof(hints));
	/* set-up hints structure */
	hints.ai_family   = af;
	hints.ai_flags    = AI_PASSIVE | AI_NUMERICHOST;
	hints.ai_socktype = SOCK_DGRAM;
	hints.ai_protocol = IPPROTO_UDP;

	error = getaddrinfo(local ? addr : NULL, serv, &hints, &res);
	if (error) {
#ifdef WIN32
		DEBUG_WARNING("listen: getaddrinfo: wsaerr=%d\n",
			      WSAGetLastError());
#endif
		DEBUG_WARNING("listen: getaddrinfo: %s:%s (%s)\n",
			      addr, serv, gai_strerror(error));
		err = EADDRNOTAVAIL;
		goto out;
	}

	for (r = res; r; r = r->ai_next) {
		int fd = -1;

		if (us->fd > 0)
			continue;

		DEBUG_INFO("listen: for: af=%d addr=%j\n",
			   r->ai_family, r->ai_addr);

		fd = SOK_CAST socket(r->ai_family, SOCK_DGRAM, IPPROTO_UDP);
		if (fd < 0) {
			err = errno;
			continue;
		}

		err = net_sockopt_blocking_set(fd, false);
		if (err) {
			DEBUG_WARNING("udp listen: nonblock set: %s\n",
				      strerror(err));
			(void)close(fd);
			continue;
		}

		if (bind(fd, r->ai_addr, SIZ_CAST r->ai_addrlen) < 0) {
			err = errno;
			DEBUG_INFO("listen: bind(): %s (%J)\n",
				   strerror(err), local);
			(void)close(fd);
			continue;
		}

		/* Can we do both IPv4 and IPv6 on same socket? */
		if (AF_INET6 == r->ai_family) {
			struct sa sa;
			int on = 1;  /* assume v6only */

#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
			socklen_t on_len = sizeof(on);
			if (0 != getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
					    (char *)&on, &on_len)) {
				on = 1;
			}
#endif
			/* Extra check for unspec addr - MAC OS X/Solaris */
			if (0==sa_set_sa(&sa, r->ai_addr) && sa_is_any(&sa)) {
				on = 1;
			}
			DEBUG_INFO("socket %d: IPV6_V6ONLY is %d\n", fd, on);
			if (on) {
				us->fd6 = fd;
				continue;
			}
		}

		/* OK */
		us->fd = fd;
		break;
	}

	freeaddrinfo(res);

	/* We must have at least one socket */
	if (-1 == us->fd && -1 == us->fd6) {
		if (0 == err)
			err = EADDRNOTAVAIL;
		goto out;
	}

	err = udp_thread_attach(us);
	if (err)
		goto out;

	us->rh   = rh ? rh : dummy_udp_recv_handler;
	us->arg  = arg;
	us->rxsz = UDP_RXSZ_DEFAULT;

 out:
	if (err)
		mem_deref(us);
	else
		*usp = us;

	return err;
}
Example #3
0
/**
 * Print a formatted string
 *
 * @param fmt Formatted string
 * @param ap  Variable argument
 * @param vph Print handler
 * @param arg Handler argument
 *
 * @return 0 if success, otherwise errorcode
 *
 * Extensions:
 *
 * <pre>
 *   %b  (char *, size_t)        Buffer string with pointer and length
 *   %r  (struct pl)             Pointer-length object
 *   %w  (uint8_t *, size_t)     Binary buffer to hexadecimal format
 *   %j  (struct sa *)           Socket address - address part only
 *   %J  (struct sa *)           Socket address and port - like 1.2.3.4:1234
 *   %H  (re_printf_h *, void *) Print handler with argument
 *   %v  (char *fmt, va_list *)  Variable argument list
 *   %m  (int)                   Describe an error code
 * </pre>
 *
 * Reserved for the future:
 *
 *   %k
 *   %y
 *
 */
int re_vhprintf(const char *fmt, va_list ap, re_vprintf_h *vph, void *arg)
{
	uint8_t base, *bptr;
	char pch, ch, num[NUM_SIZE], addr[64], msg[256];
	enum length_modifier lenmod = LENMOD_NONE;
	struct re_printf pf;
	bool fm = false, plr = false;
	const struct pl *pl;
	size_t pad = 0, fpad = -1, len, i;
	const char *str, *p = fmt, *p0 = fmt;
	const struct sa *sa;
	re_printf_h *ph;
	void *ph_arg;
	va_list *apl;
	int err = 0;
	void *ptr;
	uint64_t n;
	int64_t sn;
	bool uc = false;
	double dbl;

	if (!fmt || !vph)
		return EINVAL;

	pf.vph = vph;
	pf.arg = arg;

	for (;*p && !err; p++) {

		if (!fm) {
			if (*p != '%')
				continue;

			pch = ' ';
			plr = false;
			pad = 0;
			fpad = -1;
			lenmod = LENMOD_NONE;
			uc = false;

			if (p > p0)
				err |= vph(p0, p - p0, arg);

			fm = true;
			continue;
		}

		fm = false;
		base = 10;

		switch (*p) {

		case '-':
			plr = true;
			fm  = true;
			break;

		case '.':
			fpad = pad;
			pad = 0;
			fm = true;
			break;

		case '%':
			ch = '%';

			err |= vph(&ch, 1, arg);
			break;

		case 'b':
			str = va_arg(ap, const char *);
			len = va_arg(ap, size_t);

			err |= write_padded(str, str ? len : 0, pad, ' ',
					    plr, NULL, vph, arg);
			break;

		case 'c':
			ch = va_arg(ap, int);

			err |= write_padded(&ch, 1, pad, ' ', plr, NULL,
					    vph, arg);
			break;

		case 'd':
		case 'i':
			switch (lenmod) {

			case LENMOD_SIZE:
				sn = va_arg(ap, ssize_t);
				break;

			default:
			case LENMOD_LONG_LONG:
				sn = va_arg(ap, signed long long);
				break;

			case LENMOD_LONG:
				sn = va_arg(ap, signed long);
				break;

			case LENMOD_NONE:
				sn = va_arg(ap, signed);
				break;
			}

			len = local_itoa(num, (sn < 0) ? -sn : sn, base,
					 false);

			err |= write_padded(num, len, pad,
					    plr ? ' ' : pch, plr,
					    (sn < 0) ? prfx_neg : NULL,
					    vph, arg);
			break;

		case 'f':
		case 'F':
			dbl = va_arg(ap, double);

			if (fpad == (size_t)-1) {
				fpad = pad;
				pad  = 0;
			}

			if (isinf(dbl)) {
				err |= write_padded("inf", 3, fpad,
						    ' ', plr, NULL, vph, arg);
			}
			else if (isnan(dbl)) {
				err |= write_padded("nan", 3, fpad,
						    ' ', plr, NULL, vph, arg);
			}
			else {
				len = local_ftoa(num, dbl,
						 pad ? min(pad, DEC_SIZE) : 6);

				err |= write_padded(num, len, fpad,
						    plr ? ' ' : pch, plr,
						    (dbl<0) ? prfx_neg : NULL,
						    vph, arg);
			}
			break;

		case 'H':
			ph     = va_arg(ap, re_printf_h *);
			ph_arg = va_arg(ap, void *);

			if (ph)
				err |= ph(&pf, ph_arg);
			break;

		case 'l':
			++lenmod;
			fm = true;
			break;

		case 'm':
			str = str_error(va_arg(ap, int), msg, sizeof(msg));
			err |= write_padded(str, str_len(str), pad,
					    ' ', plr, NULL, vph, arg);
			break;

		case 'p':
			ptr = va_arg(ap, void *);

			if (ptr) {
				len = local_itoa(num, (unsigned long int)ptr,
						 16, false);
				err |= write_padded(num, len, pad,
						    plr ? ' ' : pch, plr,
						    prfx_hex, vph, arg);
			}
			else {
				err |= write_padded(str_nil,
						    sizeof(str_nil) - 1,
						    pad, ' ', plr, NULL,
						    vph, arg);
			}
			break;

		case 'r':
			pl = va_arg(ap, const struct pl *);

			err |= write_padded(pl ? pl->p : NULL,
					    (pl && pl->p) ? pl->l : 0,
					    pad, ' ', plr, NULL, vph, arg);
			break;

		case 's':
			str = va_arg(ap, const char *);
			err |= write_padded(str, str_len(str), pad,
					    ' ', plr, NULL, vph, arg);
			break;

		case 'X':
			uc = true;
			/*@fallthrough@*/
		case 'x':
			base = 16;
			/*@fallthrough@*/
		case 'u':
			switch (lenmod) {

			case LENMOD_SIZE:
				n = va_arg(ap, size_t);
				break;

			default:
			case LENMOD_LONG_LONG:
				n = va_arg(ap, unsigned long long);
				break;

			case LENMOD_LONG:
				n = va_arg(ap, unsigned long);
				break;

			case LENMOD_NONE:
				n = va_arg(ap, unsigned);
				break;
			}

			len = local_itoa(num, n, base, uc);

			err |= write_padded(num, len, pad,
					    plr ? ' ' : pch, plr, NULL,
					    vph, arg);
			break;

		case 'v':
			str = va_arg(ap, char *);
			apl = va_arg(ap, va_list *);

			if (!str || !apl)
				break;

			err |= re_vhprintf(str, *apl, vph, arg);
			break;

		case 'W':
			uc = true;
			/*@fallthrough@*/
		case 'w':
			bptr = va_arg(ap, uint8_t *);
			len = va_arg(ap, size_t);

			len = bptr ? len : 0;
			pch = plr ? ' ' : pch;

			while (!plr && pad-- > (len * 2))
				err |= vph(&pch, 1, arg);

			for (i=0; i<len; i++) {
				const uint8_t v = *bptr++;
				uint32_t l = local_itoa(num, v, 16, uc);
				err |= write_padded(num, l, 2, '0',
						    false, NULL, vph, arg);
			}

			while (plr && pad-- > (len * 2))
				err |= vph(&pch, 1, arg);

			break;

		case 'z':
			lenmod = LENMOD_SIZE;
			fm = true;
			break;

		case 'j':
			sa = va_arg(ap, struct sa *);
			if (!sa)
				break;
			if (sa_ntop(sa, addr, sizeof(addr))) {
				err |= write_padded("?", 1, pad, ' ',
						    plr, NULL, vph, arg);
				break;
			}
			err |= write_padded(addr, strlen(addr), pad, ' ',
					    plr, NULL, vph, arg);
			break;


		case 'J':
			sa = va_arg(ap, struct sa *);
			if (!sa)
				break;
			if (sa_ntop(sa, addr, sizeof(addr))) {
				err |= write_padded("?", 1, pad, ' ',
						    plr, NULL, vph, arg);
				break;
			}

#ifdef HAVE_INET6
			if (AF_INET6 == sa_af(sa)) {
				ch = '[';
				err |= vph(&ch, 1, arg);
			}
#endif
			err |= write_padded(addr, strlen(addr), pad, ' ',
					    plr, NULL, vph, arg);
#ifdef HAVE_INET6
			if (AF_INET6 == sa_af(sa)) {
				ch = ']';
				err |= vph(&ch, 1, arg);
			}
#endif

			ch = ':';
			err |= vph(&ch, 1, arg);
			len = local_itoa(num, sa_port(sa), 10, false);
			err |= write_padded(num, len, pad,
					    plr ? ' ' : pch, plr, NULL,
					    vph, arg);

			break;

		default:
			if (('0' <= *p) && (*p <= '9')) {
				if (!pad && ('0' == *p)) {
					pch = '0';
				}
				else {
					pad *= 10;
					pad += *p - '0';
				}
				fm = true;
				break;
			}

			ch = '?';

			err |= vph(&ch, 1, arg);
			break;
		}

		if (!fm)
			p0 = p + 1;
	}

	if (!fm && p > p0)
		err |= vph(p0, p - p0, arg);

	return err;
}
Example #4
0
File: nb_dns.c Project: bro/bro
struct nb_dns_info *
nb_dns_init(char *errstr)
{
	register struct nb_dns_info *nd;

	nd = (struct nb_dns_info *)malloc(sizeof(*nd));
	if (nd == NULL) {
		snprintf(errstr, NB_DNS_ERRSIZE, "nb_dns_init: malloc(): %s",
		    my_strerror(errno));
		return (NULL);
	}
	memset(nd, 0, sizeof(*nd));
	nd->s = -1;

	/* XXX should be able to init static hostent struct some other way */
	(void)gethostbyname("localhost");

	if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
		snprintf(errstr, NB_DNS_ERRSIZE, "res_init() failed");
		free(nd);
		return (NULL);
	}

	if ( _res.nscount == 0 )
		{
		// Really?  Let's try parsing resolv.conf ourselves to see what's
		// there.  (e.g. musl libc has res_init() that doesn't actually
		// parse the config file).
		const char* config_file_path = "/etc/resolv.conf";

#ifdef _PATH_RESCONF
		config_file_path = _PATH_RESCONF;
#endif

		FILE* config_file = fopen(config_file_path, "r");

		if ( config_file )
			{
			char line[128];
			char* ns;

			while ( fgets(line, sizeof(line), config_file) )
				{
				ns = strtok(line, " \t\n");

				if ( ! ns || strcmp(ns, "nameserver") )
					continue;

				ns = strtok(0, " \t\n");

				if ( ! ns )
					continue;

				/* XXX support IPv6 */
				struct sockaddr_in a;
				memset(&a, 0, sizeof(a));
				a.sin_family = AF_INET;
				a.sin_port = htons(53);

				if ( inet_pton(AF_INET, ns, &a.sin_addr) == 1 )
					{
					memcpy(&nd->server, &a, sizeof(a));
					nd->s = socket(nd->server.ss_family, SOCK_DGRAM, 0);

					if ( nd->s < 0 )
						{
						snprintf(errstr, NB_DNS_ERRSIZE, "socket(): %s",
						         my_strerror(errno));
						fclose(config_file);
						free(nd);
						return (NULL);
						}

					if ( connect(nd->s, (struct sockaddr *)&nd->server,
					             nd->server.ss_family == AF_INET ?
					             sizeof(struct sockaddr_in) :
					             sizeof(struct sockaddr_in6)) < 0 )
						{
						char s[INET6_ADDRSTRLEN];
						sa_ntop((struct sockaddr*)&nd->server, s, INET6_ADDRSTRLEN);
						snprintf(errstr, NB_DNS_ERRSIZE, "connect(%s): %s", s,
						         my_strerror(errno));
						fclose(config_file);
						close(nd->s);
						free(nd);
						return (NULL);
						}

					fclose(config_file);
					return (nd);
					}
				}

			fclose(config_file);
			snprintf(errstr, NB_DNS_ERRSIZE, "no valid nameserver found in %s",
			         config_file_path);
			free(nd);
			return (NULL);
			}

		snprintf(errstr, NB_DNS_ERRSIZE, "resolver config file not located");
		free(nd);
		return (NULL);
		}

	int i;

	for ( i = 0; i < _res.nscount; ++i )
		{
		memcpy(&nd->server, &_res.nsaddr_list[i], sizeof(struct sockaddr_in));
		/* XXX support IPv6 */
		if ( nd->server.ss_family != AF_INET )
			continue;

		nd->s = socket(nd->server.ss_family, SOCK_DGRAM, 0);

		if ( nd->s < 0 )
			{
			snprintf(errstr, NB_DNS_ERRSIZE, "socket(): %s",
			         my_strerror(errno));
			free(nd);
			return (NULL);
			}

		if ( connect(nd->s, (struct sockaddr *)&nd->server,
	                 nd->server.ss_family == AF_INET ?
	                           sizeof(struct sockaddr_in) :
	                           sizeof(struct sockaddr_in6)) < 0 )
			{
			char s[INET6_ADDRSTRLEN];
			sa_ntop((struct sockaddr*)&nd->server, s, INET6_ADDRSTRLEN);
			snprintf(errstr, NB_DNS_ERRSIZE, "connect(%s): %s", s,
			         my_strerror(errno));
			close(nd->s);
			free(nd);
			return (NULL);
			}

		return (nd);
		}

	snprintf(errstr, NB_DNS_ERRSIZE, "no valid nameservers in resolver config");
	free(nd);
	return (NULL);
}