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! */ }
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; }
/* * The fact that this routines gets called is a first hint that * the current forwarder/nameserver is down at this point in time. * Actually, it may just be slow, be overloaded, or the network may * be congested. In any way, from our point of view it is slow or * down and thus we may gain by trying a configured backup forwarder. * * This routines marks the forwarder with the given address (if any) * with a `minus' point. If a forwarder has gathered `enough' minus points * it will be marked down, such that it will not be used for a while. * * Note that the current forwarder (T.current_fwd) is never marked down! */ void fwd_mark (struct sockaddr *sa, int up) { char *fn = "fwd_mark"; char astr[MAX_DNAME]; char bstr[MAX_DNAME]; G_List *gl; Fwd *fwd; syslog (LOG_DEBUG, "%s: start()", fn); if (!T.Fwd_list || !T.current_fwd) return; fwd = NULL; for (gl = T.Fwd_list->next; gl->list_data; gl = gl->next) { fwd = (Fwd *)gl->list_data; if (sa->sa_family != fwd->sa->sa_family) continue; #ifdef USE_INET6 if (sa->sa_family == AF_INET6) { struct sockaddr_in6 *sina, *sinb; sina = (struct sockaddr_in6 *) (fwd->sa); sinb = (struct sockaddr_in6 *) sa; if (IN6_ARE_ADDR_EQUAL(&sina->sin6_addr, &sinb->sin6_addr) && sina->sin6_port == sinb->sin6_port) { fwd->ticks += up; break; } } #endif #ifdef USE_INET4 if (sa->sa_family == AF_INET) { struct sockaddr_in *sina, *sinb; sina = (struct sockaddr_in *) (fwd->sa); sinb = (struct sockaddr_in *) sa; if (sina->sin_addr.s_addr == sinb->sin_addr.s_addr && sina->sin_port == sinb->sin_port) { fwd->ticks += up; break; } } #endif } if (!fwd) return; if (fwd->ticks < 0) fwd->ticks = 0; if (gl->list_data) syslog (LOG_DEBUG, "Mark forwarder with %d: %s ", fwd->ticks, sprint_inet(sa, astr)); if (fwd->ticks < FORWARDER_DEATH_MARK) return; else fwd->went_down_at = time(NULL); if (((Fwd *)(T.current_fwd->list_data))->went_down_at) { G_List *new_fwd; Fwd *fwd_tmp; /* * we marked current forwarder down, so * select new next valid forwarder */ new_fwd = T.current_fwd->next; fwd_tmp = (Fwd *)new_fwd->list_data; while (fwd_tmp) { if (fwd_tmp->sa && !fwd_tmp->went_down_at) break; new_fwd = new_fwd->next; fwd_tmp = (Fwd *)new_fwd->list_data; } if (!fwd_tmp || !fwd_tmp->sa) { /* * we didn't find a next valid forwarder, game over! * Note that we do not mark current forwarder down * (the current one never is) nor do we change it. * * Actually, we mark all forwarders up again! No use * discriminating between things that seem to behave * the same ;) */ new_fwd = T.Fwd_list->next; fwd_tmp = (Fwd *)new_fwd->list_data; while (fwd_tmp) { /* mark 'em `up' again */ fwd_tmp->ticks = 0; fwd_tmp->went_down_at = 0; new_fwd = new_fwd->next; fwd_tmp = (Fwd *)new_fwd->list_data; } return; } syslog (LOG_NOTICE, "Disabling forwarder %s (next %s)", sprint_inet(((Fwd *)T.current_fwd->list_data)->sa, astr), sprint_inet(fwd_tmp->sa, bstr)); T.current_fwd = new_fwd; } }
/* * Selects nameserver to initially forward incoming requests to. */ void fwd_select (void) { char *fn = "fwd_select"; char astr[MAX_DNAME]; G_List *list_tmp; Fwd *fwd_tmp; syslog (LOG_DEBUG, "%s: start()", fn); if (!T.current_fwd) { /* No forwarder selected yet, just pick first valid one */ if (!T.Fwd_list) return; T.current_fwd = T.Fwd_list->next; fwd_tmp = (Fwd *)T.current_fwd->list_data; while (fwd_tmp && !fwd_tmp->sa) { T.current_fwd = T.current_fwd->next; fwd_tmp = (Fwd *)T.current_fwd->list_data; } if (!fwd_tmp || !fwd_tmp->sa) { /* we didn't find a valid forwarder at all */ T.current_fwd = NULL; syslog (LOG_ERR, "No forwarder configured!"); return; } syslog (LOG_DEBUG, "Use initial forwarder %s", sprint_inet(fwd_tmp->sa, astr)); } else if (T.current_fwd->prev->list_data) { /* * We're not using the first nameserver listed, i.e. * we are using a backup server. After a while we should * try to go back to an earlier nameserver. */ time_t waittime, downtime, current_time; current_time = time(NULL); list_tmp = T.current_fwd->prev; fwd_tmp = (Fwd *)list_tmp->list_data; while (fwd_tmp) { waittime = (current_time - fwd_tmp->went_down_at); downtime = (time_t) (T.retry_interval); if (fwd_tmp->sa && waittime > downtime) { /* waited long enough, let's try again! */ syslog (LOG_NOTICE, "Enable forwarder %s again", sprint_inet(fwd_tmp->sa, astr)); /* for the occasion, we mark it up again */ fwd_tmp->went_down_at = 0; if (fwd_tmp->ticks > 0) fwd_tmp->ticks--; T.current_fwd = list_tmp; /* only one at a time, the rest will follow */ break; } list_tmp = list_tmp->prev; fwd_tmp = (Fwd *)list_tmp->list_data; } } syslog (LOG_DEBUG, "Current forwarder %s", sprint_inet(((Fwd *)T.current_fwd->list_data)->sa, astr)); syslog (LOG_DEBUG, "%s: end()", fn); return; }
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; }