📄 xorprtm.c
字号:
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 + -