⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xorprtm.c

📁 xorp源码hg
💻 C
📖 第 1 页 / 共 4 页
字号:
DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID pvImpLoad)
{
	BOOL bError = TRUE;

	switch (dwReason) {
	case DLL_PROCESS_ATTACH:
		DisableThreadLibraryCalls(hInstance);
		bError = (CE_Create(&g_ce) == NO_ERROR) ? TRUE : FALSE;
		break;

	case DLL_PROCESS_DETACH:
		CE_Destroy(&g_ce);
		break;

	default:
		break;
	}

	return bError;
}

/*
 * Add a route to RTMv2 based on a routing socket message.
 * XXX: We should report errors in more detail, e.g. if the
 * route could not be added because it already existed, etc.
 */
int
rtm_add_route(struct rt_msghdr *rtm, int msgsize)
{
    static const proper_msgsize = (sizeof(struct rt_msghdr) +
				  (sizeof(sockunion_t) * 3));
    sockunion_t *sa;
#ifdef IPV6_DLL
    struct in6_addr in6_dest;
    struct in6_addr in6_mask;
    struct in6_addr in6_nexthop;
#else
    struct in_addr in_dest;
    struct in_addr in_mask;
    struct in_addr in_nexthop;
    MIB_IPFORWARDROW ro;
#endif
    int retval;
    int prefix;
    DWORD result;
    RTM_NET_ADDRESS dest;
    RTM_NET_ADDRESS nexthop;
    RTM_NEXTHOP_HANDLE nhh;
    RTM_NEXTHOP_INFO nhi;
    RTM_ROUTE_HANDLE nrh;
    RTM_ROUTE_INFO ri;
    RTM_ROUTE_CHANGE_FLAGS changeFlags;

    /*
     * Sanity check message size, fields etc.
     */
    if (!rtm)
	return -1;
    if (msgsize < proper_msgsize || (rtm->rtm_msglen < proper_msgsize))
	return -1;
    if (rtm->rtm_type != RTM_ADD)
	return -1;
    if ((rtm->rtm_addrs & (RTA_DST|RTA_GATEWAY|RTA_NETMASK)) !=
	(RTA_DST|RTA_GATEWAY|RTA_NETMASK))
	return -1;

    nhh = NULL;
    nrh = NULL;

    /*
     * Extract destination, netmask and next-hop from routing
     * socket message.
     */
#ifdef IPV6_DLL
    sa = (sockunion_t *)(rtm + 1);
    in6_dest = sa->sin6.sin6_addr;
    if (sa->sa.sa_family != AF_INET6)
	return -1;
    ++sa;
    in6_nexthop = sa->sin6.sin6_addr;
    if (sa->sa.sa_family != AF_INET6)
	return -1;
    ++sa;
    in6_mask = sa->sin6.sin6_addr;
    if (sa->sa.sa_family != AF_INET6)
	return -1;
#else
    sa = (sockunion_t *)(rtm + 1);
    if (sa->sa.sa_family != AF_INET)
	return -1;
    in_dest = sa->sin.sin_addr;
    ++sa;
    if (sa->sa.sa_family != AF_INET)
	return -1;
    in_nexthop = sa->sin.sin_addr;
    ++sa;
    if (sa->sa.sa_family != AF_INET)
	return -1;
    in_mask = sa->sin.sin_addr;
#endif

#ifndef IPV6_DLL
    /*
     * Look up the next-hop in the system routing table via
     * IP Helper. If there is no directly connected route we
     * can use to reach the next-hop, then we reject this attempt
     * to add a route, as we need to know the interface index
     * of this route in order to add the new route.
     * XXX This is not good for multihop.
     * XXX IPv6!
     */
    result = GetBestRoute(in_nexthop.s_addr, INADDR_ANY, &ro);
    if (result != NO_ERROR) {
	TRACE1(NETWORK, "error: GetBestRoute() returned %d", result);
	return -1;
    }
#endif

    /*
     * Convert netmask to a prefix length.
     * Convert destination to an RTM_NET_ADDRESS.
     * Convert next-hop to an RTM_NET_ADDRESS.
     * XXX: IPv6 path needs 'get length from mask' macro.
     * XXX: IPv6 path needs interface index.
     */
#ifdef IPV6_DLL
    RTM_IPV6_LEN_FROM_MASK(prefix, in6_mask.s_addr);
    RTM_IPV6_MAKE_NET_ADDRESS(&dest, in6_dest.s_addr, prefix);
    RTM_IPV6_MAKE_NET_ADDRESS(&nexthop, in6_nexthop.s_addr, 128);
#else
    RTM_IPV4_LEN_FROM_MASK(prefix, in_mask.s_addr);
    RTM_IPV4_MAKE_NET_ADDRESS(&dest, in_dest.s_addr, prefix);
    RTM_IPV4_MAKE_NET_ADDRESS(&nexthop, in_nexthop.s_addr, 32);
    /*
     * Fill out the next-hop info structure.
     * Create the next-hop in the RTMv2 table.
     */
    ZeroMemory(&nhi, sizeof(nhi));
    nhi.InterfaceIndex = ro.dwForwardIfIndex;
    nhi.NextHopAddress = nexthop;
#endif /* IPV6_DLL */

    result = RtmAddNextHop(g_ce.hRtmHandle, &nhi, &nhh, &changeFlags);
    if (result != NO_ERROR) {
	TRACE1(NETWORK, "error %u adding nexthop", result);
	retval = -1;
	goto out;
    }

    /*
     * Fill out the RTM_ROUTE_INFO structure.
     * Attempt to add the route.
     */
    ZeroMemory(&ri, sizeof(ri));
    ri.PrefInfo.Metric = XORPRTM_RI_METRIC;
    ri.PrefInfo.Preference = XORPRTM_RI_PREF;
    ri.BelongsToViews = RTM_VIEW_MASK_UCAST;
    ri.NextHopsList.NumNextHops = 1;
    ri.NextHopsList.NextHops[0] = nhh;
    changeFlags = 0;

    result = RtmAddRouteToDest(g_ce.hRtmHandle, &nrh, &dest, &ri, INFINITE,
			       NULL, 0, NULL, &changeFlags);
    if (result != NO_ERROR) {
	TRACE1(NETWORK, "error %u adding route", result);
	retval = -1;
	goto out;
    }

    retval = 0;

out:
    if (nrh != NULL)
	RtmReleaseRoutes(g_ce.hRtmHandle, 1, &nrh);
    if (nhh != NULL)
	RtmReleaseNextHops(g_ce.hRtmHandle, 1, &nhh);

    return (retval);
}

/*
 * Delete a route from RTMv2 based on a routing socket message.
 * XXX: We should report errors in more detail, e.g. if the
 * route could not be added because it already existed, etc.
 */
int
rtm_delete_route(struct rt_msghdr *rtm, int msgsize)
{
    static const min_msgsize = (sizeof(struct rt_msghdr) +
			       (sizeof(sockunion_t) * 2));
    sockunion_t *sa;
    struct in_addr in_dest;
    struct in_addr in_mask;
    int found;
    int i;
    int prefix;
    int retval;
    DWORD result;
    RTM_DEST_INFO di;
    RTM_NET_ADDRESS dest;
    RTM_ROUTE_CHANGE_FLAGS changeflags;

    /*
     * Sanity check message size, fields etc.
     */
    if (!rtm)
	return -1;
    if (msgsize < min_msgsize || (rtm->rtm_msglen < min_msgsize))
	return -1;
    if (rtm->rtm_type != RTM_DELETE)
	return -1;
    if ((rtm->rtm_addrs & (RTA_DST|RTA_NETMASK)) != (RTA_DST|RTA_NETMASK))
	return -1;
    /*
     * Extract destination, netmask and next-hop from routing
     * socket message.
     * XXX: bsd's delete order is: <DST,GATEWAY,NETMASK>
     * XXX: we don't check to see if gateway is present and
     * if so we do not handle it correctly.
     */
    sa = (sockunion_t *)(rtm + 1);
    in_dest = sa->sin.sin_addr;
    ++sa;
    in_mask = sa->sin.sin_addr;

    /*
     * Convert netmask to a prefix length.
     * Convert destination to an RTM_NET_ADDRESS.
     */
    RTM_IPV4_LEN_FROM_MASK(prefix, in_mask.s_addr);
    RTM_IPV4_MAKE_NET_ADDRESS(&dest, in_dest.s_addr, prefix);

    /*
     * Look up the route to be deleted in RTMv2, from those
     * which belong to our protocol, in the unicast view.
     */
    ZeroMemory(&di, sizeof(di));
    di.DestAddress = dest;
    result = RtmGetExactMatchDestination(g_ce.hRtmHandle, &dest, 
					 RTM_THIS_PROTOCOL,
					 RTM_VIEW_MASK_UCAST, &di);
    if (result != NO_ERROR) {
	TRACE1(NETWORK, "error %u looking up route to delete", result);
	retval = -1;
	goto out;
    }
    i = 0;
    found = 0;
    for (i = 0; i < di.NumberOfViews; i++) {
    	if (di.ViewInfo[i].ViewId == RTM_VIEW_ID_UCAST) {
	    /*
	     * Return a match only if the unicast view for our protocol
	     * contains a single next-hop route to the destination.
	     */
	    if (di.ViewInfo[i].NumRoutes == 1)
		found = 1;
	    break;
	}
    }
    if (!found) {
	TRACE0(NETWORK, "route not found in table");
	retval = -1;
	goto out;
    }

    result = RtmDeleteRouteToDest(g_ce.hRtmHandle, di.ViewInfo[i].Route,
				  &changeflags);
    if (result != NO_ERROR) {
	TRACE1(NETWORK, "error %u deleting route", result);
	retval = -1;
	goto out;
    }

    retval = 0;

out:
    return (retval);
}

int
rtm_ifannounce(LPWSTR ifname, DWORD ifindex, int what)
{
    WCHAR fnameW[IFNAMSIZ];
    struct if_announcemsghdr *ifa;
    int result;
    int retval;

    TRACE3(ENTER, "Entering rtm_ifannounce %S %d %d", ifname, ifindex, what);

    ifa = NULL;
    retval = -1;

    if ((what != IFAN_ARRIVAL) && (what != IFAN_DEPARTURE)) {
	goto out;
    }

    ifa = malloc(sizeof(*ifa));
    if (ifa == NULL) {
	goto out;
    }
    ifa->ifan_name[0] = '\0';

    /*
     * If this is a new interface, then look up the FriendlyName from
     * the unicode GUID name; convert Unicode to ASCII afterwards.
     * If the caller didn't supply this, the error is fatal to this function.
     * If we can't find it, the error is non-fatal to this function.
     *
     * XXX: The very fact that we don't provide the interface name here
     * is a limitation to do with how the notifications work in the
     * Microsoft stack. It only tells us the interface index when
     * the interface goes away. XORP currently depends on both for
     * interface deletion. We could look it up from the transport,
     * but it's more work to deliver redundant information.
     */
    if (what == IFAN_ARRIVAL) {
	if (ifname == NULL)
	    goto out;

	result = MprConfigGetFriendlyName(g_ce.hMprConfig, ifname, fnameW,
					  sizeof(fnameW));
	if (result != NO_ERROR) {
	    TRACE1(NETWORK, "can't find friendlyname for ifname %S", ifname);
	} else {
	    wcstombs(ifa->ifan_name, fnameW, IFNAMSIZ);
	}
    }

    /*
     * Fill our the rest of the interface announcement and send it to
     * all connected clients.
     */
    ifa->ifan_msglen = sizeof(*ifa);
    ifa->ifan_version = RTM_VERSION;	/* XXX should set to 0 or ignore */
    ifa->ifan_type = RTM_IFANNOUNCE;
    ifa->ifan_index = ifindex;
    ifa->ifan_what = what;

    broadcast_pipe_message(ifa, sizeof(*ifa));

    retval = 0;

out:
    if (ifa != NULL)
	free(ifa);

    TRACE0(ENTER, "Leaving rtm_ifannounce");

    return (retval);
}

int
rtm_ifinfo(DWORD ifindex, int up)
{
    struct if_msghdr *ifm;
    int result;
    int retval;

    TRACE2(ENTER, "Entering rtm_ifinfo %d %d", ifindex, up);

    ifm = NULL;
    retval = -1;

    ifm = malloc(sizeof(*ifm));
    if (ifm == NULL) {
	goto out;
    }

    /*
     * Fill our the rest of the interface announcement and send it to
     * all connected clients.
     */
    ifm->ifm_msglen = sizeof(*ifm);
    ifm->ifm_version = RTM_VERSION;
    ifm->ifm_type = RTM_IFANNOUNCE;
    ifm->ifm_addrs = 0;
    ifm->ifm_flags = 0;
    ifm->ifm_index = ifindex;
    ifm->ifm_data.ifi_link_state = (up ? LINK_STATE_UP : LINK_STATE_DOWN);

    broadcast_pipe_message(ifm, sizeof(*ifm));

    retval = 0;

out:
    if (ifm != NULL)
	free(ifm);

    TRACE0(ENTER, "Leaving rtm_ifinfo");

    return (retval);
}

/*
 * Send one RTM_NEWADDR message for each IPv4 address we've found
 * in the binding message. We ignore pbind->RemoteAddress for now.
 *
 * XXX: This does not work like BSD's notifications; again, if we
 * wish to send changes, like routes, we need to maintain state,
 * as the RTMv2 APIs send the entire state of the interface's
 * address list each time.
 *
 * For this reason it's probably better to use IP Helper as
 * the means of interface information discovery (with
 * GetAdaptersAddresses()).
 */
int
rtm_newaddr(DWORD ifindex,
#ifdef IPV6_DLL
	    PIPV6_ADAPTER_BINDING_INFO pbind
#else
	    PIP_ADAPTER_BINDING_INFO pbind
#endif
)
{
    static const msgsize =
sizeof(struct ifa_msghdr) + (sizeof(sockunion_t) * 2);
    struct ifa_msghdr *ifam;
    sockunion_t *sa;
    sockunion_t *sa2;
    int i;
    int result;
    int retval;

    TRACE2(ENTER, "Entering rtm_newaddr %d %p", ifindex, pbind);

    retval = -1;
    ifam = NULL;

    if (pbind == NULL)
	goto out;
    if (pbind->AddressCount == 0)
	goto out;

    ifam = malloc(sizeof(*ifam));
    if (ifam == NULL)
	goto out;

    sa = (sockunion_t *)(ifam + 1);
    sa2 = (sa + 1);

    for (i = 0; i < pbind->AddressCount; i++) {
	ifam->ifam_msglen = msgsize;
	ifam->ifam_version = RTM_VERSION;
	ifam->ifam_type = RTM_NEWADDR;
	ifam->ifam_addrs = RTA_DST | RTA_NETMASK;
	ifam->ifam_flags = 0;
	ifam->ifam_index = ifindex;
	ifam->ifam_metric = 0;
#ifdef IPV6_DLL
	sa->sin6.sin6_family = AF_INET6;
	sa->sin6.sin6_addr.s_addr = pbind->Address[i].Address;
	sa2->sin6.sin6_family = AF_INET6;
	sa2->sin6.sin6_addr.s_addr = pbind->Address[i].Mask;
#else
	sa->sin.sin_family = AF_INET;
	sa->sin.sin_addr.s_addr = pbind->Address[i].Address;
	sa2->sin.sin_family = AF_INET;
	sa2->sin.sin_addr.s_addr = pbind->Address[i].Mask;
#endif

	broadcast_pipe_message(ifam, msgsize);
    }

    retval = 0;

out:
    if (ifam != NULL)
	free(ifam);

    TRACE0(ENTER, "Leaving rtm_newaddr");

    return (retval);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -