Пример #1
0
int net_mesg_send (Nia *ni, u_char *mesg, int mesg_len,
		   struct sockaddr *sa_p) {
	const char *fn = "net_mesg_send()";

	if (!ni) {
#ifdef USE_INET4
		if (sa_p->sa_family == AF_INET)
			ni = (Nia *) NI_wildcard->list_data;
#endif
#ifdef USE_INET6
		if (sa_p->sa_family == AF_INET6)
			ni = (Nia *) NI_wildcard6->list_data;
#endif
	}

	if (!ni || ni->udp_sock < 0) {
		syslog (LOG_WARNING, "%s: no socket to send message over", fn);
		return -1;
	}

#ifdef USE_INET4
	if (ni->sa_p->sa_family == AF_INET && sa_p->sa_family == AF_INET)
		return sendto (ni->udp_sock, mesg, mesg_len, 0, sa_p,
			       SOCKADDR_SIZEOF (*sa_p));
#endif

#ifdef USE_INET6
	if (ni->sa_p->sa_family == AF_INET6 && sa_p->sa_family == AF_INET6)
		return sendto (ni->udp_sock, mesg, mesg_len, 0, sa_p,
			       SOCKADDR_SIZEOF (*sa_p));
#endif

	return -1;
}
Пример #2
0
static int net_ifc_cmp (struct ifconf *ifc1, struct ifconf *ifc2) {
	struct ifreq *ifr_p1;
	struct ifreq *ifr_p2;
	u_char *cp1;
	u_char *cp2;

	if (ifc1->ifc_len != ifc2->ifc_len) {
		if (T.debug > 4) 
			syslog (LOG_DEBUG, "net_ifc_cmp(): lengths differ");
		return 1;
	}

	cp1 = ifc1->ifc_buf;
	cp2 = ifc2->ifc_buf;

	while (*cp1 && *cp2) {
		ifr_p1 = (struct ifreq *) cp1;
		ifr_p2 = (struct ifreq *) cp2;

		cp1 = cp1 + IFNAMSIZ + SOCKADDR_SIZEOF (ifr_p1->ifr_addr);
		cp2 = cp2 + IFNAMSIZ + SOCKADDR_SIZEOF (ifr_p2->ifr_addr);

		if (T.debug > 4) {
			char astr[MAX_DNAME], bstr[MAX_DNAME];

			sprint_inet(&ifr_p1->ifr_addr, astr);
			sprint_inet(&ifr_p2->ifr_addr, bstr);
			
			syslog (LOG_DEBUG, "net_ifc_cmp(): if1 %s, if2 %s, \
af1 %d, af2 %d, addr1 %s, addr2 %s", ifr_p1->ifr_name, ifr_p2->ifr_name, \
ifr_p1->ifr_addr.sa_family, ifr_p1->ifr_addr.sa_family, astr, bstr);
		}

#ifdef USE_INET4
		if (ifr_p1->ifr_addr.sa_family != AF_INET &&
		    ifr_p2->ifr_addr.sa_family != AF_INET)
#endif
#ifdef USE_INET6
			if (ifr_p1->ifr_addr.sa_family != AF_INET6 &&
		    	    ifr_p2->ifr_addr.sa_family != AF_INET6)
#endif
				continue; /* skip */

		/* comparison only AF_INET and AF_INET6 */
		if (ifr_p1->ifr_addr.sa_family != ifr_p2->ifr_addr.sa_family)
			return 1;

		if (strcmp (ifr_p1->ifr_name, ifr_p2->ifr_name))
			return 1;

		if (memcmp (&(ifr_p1->ifr_addr), &(ifr_p2->ifr_addr),
			    SOCKADDR_SIZEOF (ifr_p1->ifr_addr)))
			return 1;
	}

	return 0; /* equal! */
}
Пример #3
0
static Nia *nia_alloc (struct sockaddr *sa_p, int usock, int tsock) {
	Nia *ni;

	ni = (Nia *) malloc (sizeof (Nia));
	if (!ni)
		return NULL;

	if (sa_p) {
		ni->sa_p =
			(struct sockaddr *) malloc (SOCKADDR_SIZEOF (*sa_p));
		if (!ni->sa_p) {
			free (ni);
			return NULL;
		}
		memcpy (ni->sa_p, sa_p, SOCKADDR_SIZEOF (*sa_p));
	} else
		ni->sa_p = NULL;

	ni->udp_sock = usock;
	ni->tcp_sock = tsock;
	return ni;
}
/*
 * When a new query is received over a UDP socket from a client, the
 * udp_response state machine is started. See also ev_udp_in_read(),
 * which is the only place from where udp_response_start() is called.
 *
 * udp_response_start() starts a new transaction. First creates a new
 * root context for it, and starts the forwarding of the original query.
 *
 *	forwarding is performed by starting a new child request, which
 *	if all goes well result in some resource records in our context.
 *
 * when the forwarded request finished successfully, udp_response_finish()
 * is responsible for interpreting it and sending a response back to the client.
 *
 */
int udp_response_start (u_char *mesg_buf, int mesg_len, struct sockaddr *sa_p,
			Nia *inif) {
	const char *fn = "udp_response_start()";
	Context *cont;

	syslog (LOG_DEBUG, "%s: start", fn);

	/* create context */
	cont = context_create();
	if (!cont)
		return (response_abort (cont, -1));

	cont->mesg.p = mesg_buf;
	cont->mesg_len = mesg_len;
	cont->wp = mesg_buf + mesg_len;	/* just after the answer section */
	cont->q_id = cont->mesg.hdr->id;
	cont->netifaddr = nia_copy (inif);
	memcpy (cont->peer, sa_p, SOCKADDR_SIZEOF(*sa_p));

	if (cont->mesg.hdr->opcode == OP_QUERY) {
		syslog (LOG_DEBUG, "%s: OPCODE = OP_QUERY", fn);

		/* query-response specific variables */
		cont->process = udp_response_recursive_process;
		cont->retry = udp_response_recursive_retry;

		/* do the forwarding, send request to forwarder */
		switch (request_start (cont, QUERY_TCP)) {
		case 0:
			/* We got a response */
			return (0);
		case 1:
			/* Something wrong with the query */
			cont->mesg.hdr->rcode = RC_FMTERR;
			return (udp_response_finish (cont));
		default:
			/* We failed ourselves somehow */
			cont->mesg.hdr->rcode = RC_SERVERERR;
			return (udp_response_finish (cont));
		}
	} else {
		syslog (LOG_NOTICE, "%s: OPCODE unknown(%d)", fn,
			cont->mesg.hdr->opcode);
		cont->mesg.hdr->rcode = RC_NIMP;
		return udp_response_finish (cont);
	}

	/* NOTREACHED */
	return 0;
}
Пример #5
0
int net_mesg_socket (Nia *ni) {
	const char *fn = "net_mesg_socket()";
	char astr[MAX_DNAME];
	const int on = 1;
	int sock;

	ni->udp_sock = -1;

	sock = socket (ni->sa_p->sa_family, SOCK_DGRAM, 0);
	if (sock < 0) {
		syslog (LOG_ERR, "%s: socket open failed: %m", fn);
		return -1;
	}
	if (T.debug > 4)
		syslog (LOG_DEBUG, "%s: socket open(fd = %d)", fn, sock);

	if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
			(char *) &on, sizeof (on)))
		syslog (LOG_WARNING, "setsockopt: %m");


	if (bind (sock, ni->sa_p, SOCKADDR_SIZEOF (*ni->sa_p)) < 0) {
		syslog (LOG_ERR, "Can not bind datagram socket: %m");
		close (sock);
		return -1;
	}

	/* if no port set, then it is for outgoing messages only */
	if (((struct sockaddr_in *)ni->sa_p)->sin_port) {
		sprint_inet(ni->sa_p, astr);
		syslog (LOG_NOTICE, "Listening on %s for UDP", astr);
	}

#ifdef USE_INET6
#ifdef IPV6_USE_MIN_MTU
	if (ni->sa_p->sa_family == AF_INET6) {
		const int on = 1;

		/* ignore error */
		(void)setsockopt(sock, IPPROTO_IPV6,
			IPV6_USE_MIN_MTU, &on, sizeof(on));
	}
#endif
#endif

	ni->udp_sock = sock;
	return sock;
}
Пример #6
0
int net_stream_socket (Nia *ni) {
	const char *fn = "net_stream_socket()";
	char astr[MAX_DNAME];
	const int on = 1;
	int sock;

	ni->tcp_sock = -1;

	/* if no port set, do nothing for TCP */
	if (!((struct sockaddr_in *)ni->sa_p)->sin_port)
		return -1;

	sock = socket (ni->sa_p->sa_family, SOCK_STREAM, 0);
	if (sock < 0) {
		syslog (LOG_ERR, "%s: socket open failed: %m", fn);
		return -1;
	}
	if (T.debug > 4)
		syslog (LOG_DEBUG, "%s: socket open(fd = %d)", fn, sock);

	if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
			(char *) &on, sizeof (on)))
		syslog (LOG_WARNING, "setsockopt: %m");

	if (bind (sock, ni->sa_p, SOCKADDR_SIZEOF (*ni->sa_p)) != 0) {
		syslog (LOG_ERR, "Can't bind TCP socket: %m");
		close (sock);
		return -1;
	}

	if (ioctl (sock, FIONBIO, (char *) &on) < 0) {
		syslog (LOG_ERR, "Can't ioctl on service socket: %m");
		return -1;
	}

	if (listen (sock, 5) != 0) {
		syslog (LOG_ERR, "Listen failed: %m");
		close (sock);
		return -1;
	}

	sprint_inet(ni->sa_p, astr);
	syslog (LOG_NOTICE, "Listening on %s for TCP", astr);

	ni->tcp_sock = sock;
	return sock;
}
Пример #7
0
int udp_request_start (struct context *cont) {
	char *fn = "udp_request_start()";
	struct sockaddr *sa;
	int timeout;

	syslog (LOG_DEBUG, "%s: start", fn);

        cont->process = udp_request_process;
        cont->retry = udp_request_retry;

	if (cont->mesg_len > MAX_PACKET) {
		syslog (LOG_NOTICE, "Query to big for UDP datagram.");
		return (request_abort (cont, 1)); /* try TCP instead? */
	}

	sa = (struct sockaddr *) cont->current_ns->list_data;
	if (net_mesg_send (NULL, cont->mesg.p, cont->mesg_len, sa) < 0) {
		syslog (LOG_NOTICE, "send failed: %m");

		/* force immediate retry */
		timeout = 0;
		syslog (LOG_DEBUG, "%s: force retry at zero timeout", fn);
	} else {
		/* put me to input list */
		if (ev_udp_in_register (cont, sa,
					SOCKADDR_SIZEOF (*sa), cont->q_id) < 0)
			return (request_abort (cont, -1));

		timeout = cont->timeout;
		syslog (LOG_DEBUG, "Query times out in %d seconds", timeout);
	}

	/* put me on timeout event queue */
	if (context_timeout_register (cont, timeout) < 0) 
		return (request_abort (cont, -1));

	syslog (LOG_DEBUG, "%s: end", fn);
	/* SUCCESS */
	return 0;
}
Пример #8
0
int tcp_response_start (int sock, struct sockaddr *sa_p) {
	const char *fn = "tcp_response_start()";
	Context *cont;

	syslog (LOG_DEBUG, "%s: start", fn);

	cont = context_create();
	if (!cont)
		return (response_abort (cont, -1));

	cont->process = tcp_response_readlen_process;
	cont->retry = tcp_response_readlen_retry;
	memcpy (cont->peer, sa_p, SOCKADDR_SIZEOF(*sa_p));

	cont->conn_sock = sock;
	cont->timeout = TCP_SRV_TIMEOUT;

	if (!context_timeout_register (cont, cont->timeout) &&
	    !ev_tcp_conn_in_register (cont->conn_sock, cont))
			return 0; /* SUCCESS */

	return (response_abort (cont, -1));
}
Пример #9
0
G_List *fwd_socketlist (void) {
	char *fn = "fwd_socketlist";
	G_List *socklist, *gl;
	Fwd *fwd;

	syslog (LOG_DEBUG, "%s: start()", fn);

	if (!T.Fwd_list || !T.current_fwd)
		return NULL;

	socklist = list_init();

	/*
	 * We cycle through all forwarders, starting with the `current' one.
	 * We skip all those that are currently marked down or without proper
	 * socket address.
	 */
        for (gl = T.current_fwd; gl->next != T.current_fwd; gl = gl->next) {
		if (!gl->list_data)
			continue;

	        fwd = (Fwd *)gl->list_data;
		if (fwd->sa && !fwd->went_down_at)  {
			struct sockaddr *sa;

			sa = malloc (sizeof(struct sockaddr_storage));
			if (!sa)
				return NULL;

			memcpy(sa, fwd->sa, SOCKADDR_SIZEOF(*fwd->sa));
			list_add_tail(socklist, sa);
		}
	}

	return socklist;
}
Пример #10
0
int udp_request_retry (Context *cont) {
	char *fn = "udp_request_retry()";
	struct sockaddr *sa;
	int len, timeout;

	syslog (LOG_DEBUG, "%s: start", fn);

	/* remove old I/O List (if it is still there) */
	sa = (struct sockaddr *) cont->current_ns->list_data;
	ev_udp_in_remove (sa, cont->q_id);

	/*
	 * Fast GiveUp Hack.
	 *
	 * decisions like this should only be made in request.c,
	 * so this hack is ugly too.
	 */
	if (cont->q_type == RT_AAAA || cont->q_type == RT_A6) {
		/*
		 * Some nameservers just do not like IPv6
		 * address records. We guess that is the case
		 * here and tell the parent to continue if it
		 * can.
		 *
		 * We perform the code of request_finish()
		 * here, but without the parsing of the
		 * response (we have none).
		 *
		 * Note that this means that a timeout for a IPv6
		 * address record request never causes a shift to
		 * the next forwarder! Seems reasonable in the
		 * for the majority of cases.
		 */

		syslog (LOG_DEBUG, "Giving up quickly on IPv6 address record");

		/* re-initialize answer, nameserver, additional record lists */
		list_destroy (cont->an_list, rrset_freev);
		list_destroy (cont->ns_list, rrset_freev);
		list_destroy (cont->ar_list, rrset_freev);
		cont->an_list = list_init ();
		cont->ns_list = list_init ();
		cont->ar_list = list_init ();
		if (!cont->an_list || !cont->ns_list || !cont->ar_list)
			return request_abort (cont, -1);

		if (cont->parent) {
			syslog (LOG_DEBUG, "%s: process parent context", fn);
			cont->parent->process (cont->parent);
		}

		/* ... so we cleanup ourselves in any case */
		context_destroy (cont);

		syslog (LOG_DEBUG, "%s: return success", fn);
		return 0; /* SUCCESS */
	}

	if (request_retry (cont) < 0)
		return (request_abort (cont, -2));

	/* send/forward the message/request again */
	sa = (struct sockaddr *) cont->current_ns->list_data;
	len = net_mesg_send (NULL, cont->mesg.p, cont->mesg_len, sa);
	if (len < cont->mesg_len) {
		if (len < 0)
			syslog (LOG_NOTICE, "retry failed(default socket): %m");
		else
			syslog (LOG_NOTICE, "can't send whole datagram");
		/* forcing immediate retry */
		timeout = 0;
	} else {
		/* we retried the request, now wait for response or timeout */
		timeout = cont->timeout;
		/* put me to input list */
		if (ev_udp_in_register (cont, sa,
		     SOCKADDR_SIZEOF (*sa), cont->q_id) < 0)
			return (request_abort (cont, -1));
	}

	/* put me to timeout list */
	if (context_timeout_register (cont, timeout) < 0)
		return (request_abort (cont, -1));

	/* no state change... */
	syslog (LOG_DEBUG, "%s: end", fn);
	return 0;
}
Пример #11
0
static int net_get_ifaddrs (G_List *list_head, int port) {
	const char *fn = "net_get_ifaddrs()";
	static struct ifconf ifc_old;
	struct ifconf ifc;
	int dummy_sock = -1, status;
	u_char buf[8192];
	u_char *cp;

	memset (buf, 0, sizeof (buf));
	ifc.ifc_len = sizeof (buf);
	ifc.ifc_buf = buf;

#ifdef USE_INET6
	if (dummy_sock < 0)
		dummy_sock = socket (AF_INET6, SOCK_STREAM, 0);
#endif
#ifdef USE_INET4
	if (dummy_sock < 0)
		dummy_sock = socket (AF_INET, SOCK_STREAM, 0);
#endif
	if (dummy_sock < 0)
		return -1;

	/*
	 * check whether list of interface addresses has changed
	 */
	if (ioctl (dummy_sock, SIOCGIFCONF, (char *) &ifc) < 0) {
		close(dummy_sock);
		syslog (LOG_ERR, "%s: get iflist error: %m", fn);
		return -1;
	}
	close(dummy_sock);

	status = 1;
	if (ifc_old.ifc_buf) {
		status = net_ifc_cmp (&ifc_old, &ifc);
		syslog (LOG_DEBUG, "%s: checked interface data %d", fn, status);
	}

	/*
	 * Interface address list changed or we got called for
	 * for the first time
	 */

	cp = buf;
	while (*cp) {
		int valid_address = 0;
		char astr[MAX_DNAME];
		struct ifreq *ifr_p;

		ifr_p = (struct ifreq *) cp;
		sprint_inet(&ifr_p->ifr_addr, astr);

#ifdef USE_INET6
		if (T.ip6 && ifr_p->ifr_addr.sa_family == AF_INET6)
			if (nia_is_in_totd_iflist(ifr_p->ifr_name))
				valid_address = 1;
#endif
#ifdef USE_INET4
		if (T.ip4 && ifr_p->ifr_addr.sa_family == AF_INET)
			if (T.ip4 && nia_is_in_totd_iflist(ifr_p->ifr_name))
				valid_address = 1;
#endif

		if (valid_address) {
			Nia *ni;

			ni = nia_alloc (&ifr_p->ifr_addr, -1, -1);
			if (!ni)
				return -1;

#ifdef USE_INET6
			if (T.ip6 && ni->sa_p->sa_family == AF_INET6) {
				struct sockaddr_in6 *sa_p;

				sa_p = (struct sockaddr_in6 *) ni->sa_p;
				sa_p->sin6_port = htons (port);
			}
#endif

#ifdef USE_INET6
			if (T.ip4 && ni->sa_p->sa_family == AF_INET) {
				struct sockaddr_in *sa_p;

				sa_p = (struct sockaddr_in *) ni->sa_p;
				sa_p->sin_port = htons (port);
			}
#endif

			if (*astr && T.debug > 3)
				syslog (LOG_DEBUG, "Found address %s on if %s",
					astr, ifr_p->ifr_name);

			/* ok! add to the list */
			if (list_add (list_head, ni) < 0)
                        	return -1;

		} else if (*astr && T.debug > 3)
			syslog (LOG_DEBUG, "Ignoring address %s on if %s",
				astr, ifr_p->ifr_name);

		/* point to next address entry in list */
		cp = cp + IFNAMSIZ + SOCKADDR_SIZEOF (ifr_p->ifr_addr);
	}

	/*
	 * preserve old buffer
	 */

	if (ifc_old.ifc_buf)
		free (ifc_old.ifc_buf);

	ifc_old.ifc_buf = malloc (ifc.ifc_len);
	if (ifc_old.ifc_buf) {
		memcpy (ifc_old.ifc_buf, buf, ifc.ifc_len);
		ifc_old.ifc_len = ifc.ifc_len;
	}

	return status;
}