void dropdead(void) { char switchifname[IFNAMSIZ] = {0}; /* We're dying, so tidy up*/ if (tRoot != NULL) { tdestroy(tRoot, free); tEntries = 0; } /* Restore interface flags*/ while (0 > npd6getwan(switchifname)) { sleep(1); } if_allmulti(switchifname, 0); if_allmulti(interfacestr, 0); close(sockicmp); close(sockpkt); flog(LOG_ERR, "Tidied up. Goodbye cruel world."); exit(0); }
void dropdead(void) { int loop; /* We're dying, so tidy up*/ /* Restore interface flags and close sockets */ for (loop=0; loop<interfaceCount; loop++) { if_allmulti(interfaces[loop].nameStr, interfaces[loop].multiStatus); close( interfaces[loop].pktSock ); close( interfaces[loop].icmpSock ); } flog(LOG_ERR, "Tidied up and now exiting. Goodbye."); exit(0); }
/* * Delete a mif from the mif table */ static int del_m6if(mifi_t *mifip) { struct mif6 *mifp = mif6table + *mifip; mifi_t mifi; struct ifnet *ifp; if (*mifip >= nummifs) return EINVAL; if (mifp->m6_ifp == NULL) return EINVAL; crit_enter(); if (!(mifp->m6_flags & MIFF_REGISTER)) { /* * XXX: what if there is yet IPv4 multicast daemon * using the interface? */ ifp = mifp->m6_ifp; if_allmulti(ifp, 0); } #ifdef notyet bzero((caddr_t)qtable[*mifip], sizeof(qtable[*mifip])); bzero((caddr_t)mifp->m6_tbf, sizeof(*(mifp->m6_tbf))); #endif bzero((caddr_t)mifp, sizeof (*mifp)); /* Adjust nummifs down */ for (mifi = nummifs; mifi > 0; mifi--) if (mif6table[mifi - 1].m6_ifp) break; nummifs = mifi; crit_exit(); #ifdef MRT6DEBUG if (mrt6debug) log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs); #endif return 0; }
/* * Delete a mif from the mif table */ static int del_m6if_locked(mifi_t *mifip) { struct mif6 *mifp = mif6table + *mifip; mifi_t mifi; struct ifnet *ifp; MIF6_LOCK_ASSERT(); if (*mifip >= nummifs) return (EINVAL); if (mifp->m6_ifp == NULL) return (EINVAL); if (!(mifp->m6_flags & MIFF_REGISTER)) { /* XXX: TODO: Maintain an ALLMULTI refcount in struct ifnet. */ ifp = mifp->m6_ifp; if_allmulti(ifp, 0); } else { if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) { if_detach(multicast_register_if6); if_free(multicast_register_if6); reg_mif_num = (mifi_t)-1; multicast_register_if6 = NULL; } } bzero((caddr_t)mifp, sizeof(*mifp)); /* Adjust nummifs down */ for (mifi = nummifs; mifi > 0; mifi--) if (mif6table[mifi - 1].m6_ifp) break; nummifs = mifi; MRT6_DLOG(DEBUG_ANY, "mif %d, nummifs %d", *mifip, nummifs); return (0); }
/* * Add a mif to the mif table */ static int add_m6if(struct mif6ctl *mifcp) { struct mif6 *mifp; struct ifnet *ifp; int error; #ifdef notyet struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi; #endif if (mifcp->mif6c_mifi >= MAXMIFS) return EINVAL; mifp = mif6table + mifcp->mif6c_mifi; if (mifp->m6_ifp) return EADDRINUSE; /* XXX: is it appropriate? */ if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > if_index) return ENXIO; ifp = ifindex2ifnet[mifcp->mif6c_pifi]; if (mifcp->mif6c_flags & MIFF_REGISTER) { if (reg_mif_num == (mifi_t)-1) { strlcpy(multicast_register_if.if_xname, "register_mif", IFNAMSIZ); multicast_register_if.if_flags |= IFF_LOOPBACK; multicast_register_if.if_index = mifcp->mif6c_mifi; reg_mif_num = mifcp->mif6c_mifi; } ifp = &multicast_register_if; } /* if REGISTER */ else { /* Make sure the interface supports multicast */ if ((ifp->if_flags & IFF_MULTICAST) == 0) return EOPNOTSUPP; crit_enter(); error = if_allmulti(ifp, 1); crit_exit(); if (error) return error; } crit_enter(); mifp->m6_flags = mifcp->mif6c_flags; mifp->m6_ifp = ifp; #ifdef notyet /* scaling up here allows division by 1024 in critical code */ mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000; #endif /* initialize per mif pkt counters */ mifp->m6_pkt_in = 0; mifp->m6_pkt_out = 0; mifp->m6_bytes_in = 0; mifp->m6_bytes_out = 0; crit_exit(); /* Adjust nummifs up if the mifi is higher than nummifs */ if (nummifs <= mifcp->mif6c_mifi) nummifs = mifcp->mif6c_mifi + 1; #ifdef MRT6DEBUG if (mrt6debug) log(LOG_DEBUG, "add_mif #%d, phyint %s\n", mifcp->mif6c_mifi, ifp->if_xname); #endif return 0; }
/* * Add a mif to the mif table */ static int add_m6if(struct mif6ctl *mifcp) { struct mif6 *mifp; struct ifnet *ifp; int error; MIF6_LOCK(); if (mifcp->mif6c_mifi >= MAXMIFS) { MIF6_UNLOCK(); return (EINVAL); } mifp = mif6table + mifcp->mif6c_mifi; if (mifp->m6_ifp != NULL) { MIF6_UNLOCK(); return (EADDRINUSE); /* XXX: is it appropriate? */ } if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index) { MIF6_UNLOCK(); return (ENXIO); } ifp = ifnet_byindex(mifcp->mif6c_pifi); if (mifcp->mif6c_flags & MIFF_REGISTER) { if (reg_mif_num == (mifi_t)-1) { ifp = if_alloc(IFT_OTHER); if_initname(ifp, "register_mif", 0); ifp->if_flags |= IFF_LOOPBACK; if_attach(ifp); multicast_register_if6 = ifp; reg_mif_num = mifcp->mif6c_mifi; /* * it is impossible to guess the ifindex of the * register interface. So mif6c_pifi is automatically * calculated. */ mifcp->mif6c_pifi = ifp->if_index; } else { ifp = multicast_register_if6; } } else { /* Make sure the interface supports multicast */ if ((ifp->if_flags & IFF_MULTICAST) == 0) { MIF6_UNLOCK(); return (EOPNOTSUPP); } error = if_allmulti(ifp, 1); if (error) { MIF6_UNLOCK(); return (error); } } mifp->m6_flags = mifcp->mif6c_flags; mifp->m6_ifp = ifp; /* initialize per mif pkt counters */ mifp->m6_pkt_in = 0; mifp->m6_pkt_out = 0; mifp->m6_bytes_in = 0; mifp->m6_bytes_out = 0; /* Adjust nummifs up if the mifi is higher than nummifs */ if (nummifs <= mifcp->mif6c_mifi) nummifs = mifcp->mif6c_mifi + 1; MIF6_UNLOCK(); MRT6_DLOG(DEBUG_ANY, "mif #%d, phyint %s", mifcp->mif6c_mifi, if_name(ifp)); return (0); }
/* * Disable IPv6 multicast forwarding. */ int X_ip6_mrouter_done(void) { mifi_t mifi; u_long i; struct mf6c *rt; struct rtdetq *rte; MROUTER6_LOCK(); if (V_ip6_mrouter == NULL) { MROUTER6_UNLOCK(); return (EINVAL); } /* * For each phyint in use, disable promiscuous reception of all IPv6 * multicasts. */ for (mifi = 0; mifi < nummifs; mifi++) { if (mif6table[mifi].m6_ifp && !(mif6table[mifi].m6_flags & MIFF_REGISTER)) { if_allmulti(mif6table[mifi].m6_ifp, 0); } } bzero((caddr_t)mif6table, sizeof(mif6table)); nummifs = 0; V_pim6 = 0; /* used to stub out/in pim specific code */ callout_stop(&expire_upcalls_ch); /* * Free all multicast forwarding cache entries. */ MFC6_LOCK(); for (i = 0; i < MF6CTBLSIZ; i++) { rt = mf6ctable[i]; while (rt) { struct mf6c *frt; for (rte = rt->mf6c_stall; rte != NULL; ) { struct rtdetq *n = rte->next; m_free(rte->m); free(rte, M_MRTABLE6); rte = n; } frt = rt; rt = rt->mf6c_next; free(frt, M_MRTABLE6); } } bzero((caddr_t)mf6ctable, sizeof(mf6ctable)); MFC6_UNLOCK(); /* * Reset register interface */ if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) { if_detach(multicast_register_if6); if_free(multicast_register_if6); reg_mif_num = (mifi_t)-1; multicast_register_if6 = NULL; } V_ip6_mrouter = NULL; V_ip6_mrouter_ver = 0; MROUTER6_UNLOCK(); MRT6_DLOG(DEBUG_ANY, "finished"); return (0); }
/* * Apply routing function on the affected upstream and downstream prefixes, * i.e. either set or clear RTF_PROXY on the cloning prefix route; all route * entries that were cloned off these prefixes will be blown away. Caller * must have acquried proxy6_lock and must not be holding nd6_mutex. */ static void nd6_prproxy_prelist_setroute(boolean_t enable, struct nd6_prproxy_prelist_head *up_head, struct nd6_prproxy_prelist_head *down_head) { struct nd6_prproxy_prelist *up, *down, *ndprl_tmp; struct nd_prefix *pr; lck_mtx_assert(&proxy6_lock, LCK_MTX_ASSERT_OWNED); lck_mtx_assert(nd6_mutex, LCK_MTX_ASSERT_NOTOWNED); SLIST_FOREACH_SAFE(up, up_head, ndprl_le, ndprl_tmp) { struct rtentry *rt; boolean_t prproxy, set_allmulti = FALSE; int allmulti_sw; struct ifnet *ifp = NULL; SLIST_REMOVE(up_head, up, nd6_prproxy_prelist, ndprl_le); pr = up->ndprl_pr; VERIFY(up->ndprl_up == NULL); NDPR_LOCK(pr); ifp = pr->ndpr_ifp; prproxy = (pr->ndpr_stateflags & NDPRF_PRPROXY); VERIFY(!prproxy || ((pr->ndpr_stateflags & NDPRF_ONLINK) && !(pr->ndpr_stateflags & NDPRF_IFSCOPE))); nd6_prproxy_sols_reap(pr); VERIFY(pr->ndpr_prproxy_sols_cnt == 0); VERIFY(RB_EMPTY(&pr->ndpr_prproxy_sols)); if (enable && pr->ndpr_allmulti_cnt == 0) { nd6_prproxy++; pr->ndpr_allmulti_cnt++; set_allmulti = TRUE; allmulti_sw = TRUE; } else if (!enable && pr->ndpr_allmulti_cnt > 0) { nd6_prproxy--; pr->ndpr_allmulti_cnt--; set_allmulti = TRUE; allmulti_sw = FALSE; } if ((rt = pr->ndpr_rt) != NULL) { if ((enable && prproxy) || (!enable && !prproxy)) RT_ADDREF(rt); else rt = NULL; NDPR_UNLOCK(pr); } else { NDPR_UNLOCK(pr); } /* Call the following ioctl after releasing NDPR lock */ if (set_allmulti && ifp != NULL) if_allmulti(ifp, allmulti_sw); NDPR_REMREF(pr); if (rt != NULL) { rt_set_proxy(rt, enable); rtfree(rt); } nd6_ndprl_free(up); } SLIST_FOREACH_SAFE(down, down_head, ndprl_le, ndprl_tmp) { struct nd_prefix *pr_up; struct rtentry *rt; boolean_t prproxy, set_allmulti = FALSE; int allmulti_sw; struct ifnet *ifp = NULL; SLIST_REMOVE(down_head, down, nd6_prproxy_prelist, ndprl_le); pr = down->ndprl_pr; pr_up = down->ndprl_up; VERIFY(pr_up != NULL); NDPR_LOCK(pr_up); ifp = pr->ndpr_ifp; prproxy = (pr_up->ndpr_stateflags & NDPRF_PRPROXY); VERIFY(!prproxy || ((pr_up->ndpr_stateflags & NDPRF_ONLINK) && !(pr_up->ndpr_stateflags & NDPRF_IFSCOPE))); NDPR_UNLOCK(pr_up); NDPR_LOCK(pr); if (enable && pr->ndpr_allmulti_cnt == 0) { pr->ndpr_allmulti_cnt++; set_allmulti = TRUE; allmulti_sw = TRUE; } else if (!enable && pr->ndpr_allmulti_cnt > 0) { pr->ndpr_allmulti_cnt--; set_allmulti = TRUE; allmulti_sw = FALSE; } if ((rt = pr->ndpr_rt) != NULL) { if ((enable && prproxy) || (!enable && !prproxy)) RT_ADDREF(rt); else rt = NULL; NDPR_UNLOCK(pr); } else { NDPR_UNLOCK(pr); } if (set_allmulti && ifp != NULL) if_allmulti(ifp, allmulti_sw); NDPR_REMREF(pr); NDPR_REMREF(pr_up); if (rt != NULL) { rt_set_proxy(rt, enable); rtfree(rt); } nd6_ndprl_free(down); } }
int main(int argc, char *argv[]) { char logfile[FILENAME_MAX] = ""; char switchifname[IFNAMSIZ] = {0}; int c, err; int pid = 0; FILE *pidfp = NULL; // Default some globals strncpy(configfile, NPD6_CONF, FILENAME_MAX); strncpy( interfacestr, NULLSTR, sizeof(NULLSTR)); memset( prefixaddrstr, 0, sizeof(prefixaddrstr)); interfaceIdx = -1; daemonize = 0; // Default black/whitelisting to OFF listType = NOLIST; // Default config file values as required naLinkOptFlag = 0; nsIgnoreLocal = 1; naRouter = 1; debug = 0; maxHops = MAXMAXHOPS; /* Parse the args */ while ((c = getopt_long(argc, argv, OPTIONS_STR, prog_opt, NULL)) > 0) { if (c==-1) break; switch (c) { case 'c': strcpy(configfile, optarg); break; case 'l': strcpy(logfile, optarg); break; case 'd': debug=1; break; case 'D': debug=2; break; case 'b': daemonize=1; break; case 'v': showVersion(); return 0; break; case 'h': showUsage(); return 0; break; } } /* Seems like about the right time to daemonize (or not) */ if (daemonize) { if (daemon(0, 0) < 0 ) { flog(LOG_ERR, "Failed to daemonize. Error: %s", strerror(errno) ); exit(1); } } pid = getpid(); if ((pidfp = fopen(NDP6PROXY_PIDFILE, "w")) != NULL) { fprintf(pidfp, "%d\n", pid); fclose(pidfp); } else { printf("**************** Open Pid file faild *********************** \r\n"); } while (0 >= strlen(prefixaddrstr)) { addr6match(NULL, NULL, 0); sleep(1); } /* Sort out where to log */ if ( strlen(logfile) ) { if (strlen(logfile) == 1 && (logfile[0]='-') ) logging = USE_STD; else logging = USE_FILE; } else { logging = USE_SYSLOG; } /* Open the log and config*/ if ( (logging == USE_FILE) && (openLog(logfile) < 0) ) { printf("Exiting. Error in setting up logging correctly.\n"); exit (1); } flog(LOG_INFO, "*********************** npd6 *****************************"); if ( readConfig(configfile) ) { flog(LOG_ERR, "Error in config file: %s", configfile); return 1; } flog(LOG_INFO, "Using normalised prefix %s/%d", prefixaddrstr, prefixaddrlen); flog(LOG_DEBUG2, "ifIndex for %s is: %d", interfacestr, interfaceIdx); err = init_sockets(); if (err) { flog(LOG_ERR, "init_sockets: failed to initialise one or both sockets."); exit(1); } /* Set allmulti on the interface */ while (0 > npd6getwan(switchifname)) { sleep(1); } if_allmulti(switchifname, TRUE); if_allmulti(interfacestr, TRUE); /* Set up signal handlers */ signal(SIGUSR1, usersignal); signal(SIGUSR2, usersignal); signal(SIGHUP, usersignal); signal(SIGINT, usersignal); signal(SIGTERM, usersignal); // Typically used by init.d scripts /* And off we go... */ dispatcher(); flog(LOG_ERR, "Fell back out of dispatcher... This is impossible."); return 0; }