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; }
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! */ }
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; }
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; }
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; }
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; }
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)); }
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; }
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; }
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; }