📄 cardif_linux_rtnetlink.c
字号:
// There may be more than one message in the packet. So, loop through!
while (remain >= sizeof(struct nlmsghdr))
{
// Make sure we have enough data for a real message.
if ((nlhead->nlmsg_len > remain) ||
((nlhead->nlmsg_len - sizeof(struct nlmsghdr)) < 0))
{
debug_printf(DEBUG_NORMAL, "Invalid netlink message!\n");
break;
}
// See what kind of message it is.
switch (nlhead->nlmsg_type)
{
case RTM_NEWLINK:
debug_printf(DEBUG_INT, "Got an RTM_NEWLINK!\n");
cardif_linux_rtnetlink_do_link(idata, nlhead,
nlhead->nlmsg_len, INT_NEW);
break;
case RTM_DELLINK:
debug_printf(DEBUG_INT, "Got an RTM_DELLINK!\n");
cardif_linux_rtnetlink_do_link(idata, nlhead,
nlhead->nlmsg_len, INT_DEL);
break;
}
// Find the aligned length of the message, so we can skip
// to the next message.
length = NLMSG_ALIGN(nlhead->nlmsg_len);
remain -= length;
nlhead = (struct nlmsghdr *) ((char *)nlhead + length);
}
// If we have anything left, then there may be a problem. So, report
// the we may have a problem.
if (remain > 0)
{
debug_printf(DEBUG_NORMAL, "Extra bytes at the end of the netlink message.\n");
}
}
// There may be situations where the wireless card driver can scan,
// but doesn't provide an event when the scan has completed. So,
// we need to check if we have data, even if we don't have an event.
return cardif_linux_rtnetlink_check_nets(idata);
}
/************************************************************
*
* We got an RTM_NEWLINK or RTM_DELLINK message, so process it, and
* decide how to proceed.
*
************************************************************/
void cardif_linux_rtnetlink_do_link(context *intdata,
struct nlmsghdr *msg, int len, int type)
{
struct ifinfomsg *ifinfo = NULL;
int nlmsg_len, rtalen, rtlen;
struct rtattr *rtattr = NULL;
if (!xsup_assert((intdata != NULL), "intdata != NULL", FALSE))
return;
if (!xsup_assert((msg != NULL), "msg != NULL", FALSE))
return;
if (len < sizeof(struct ifinfomsg))
{
debug_printf(DEBUG_NORMAL, "Netlink message too short!\n");
return;
}
// Get the actual message from the block.
ifinfo = NLMSG_DATA(msg);
// Find out how big the message is.
nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
if ((msg->nlmsg_len - nlmsg_len) < 0)
{
debug_printf(DEBUG_NORMAL, "Message inside newlink isn't valid!\n");
return;
}
rtattr = (struct rtattr *)(((char *)ifinfo) + nlmsg_len);
rtalen = RTA_ALIGN(sizeof(struct rtattr));
// Validate the attribute we have, and determine if it is for wireless,
// or wired.
while (RTA_OK(rtattr, (msg->nlmsg_len - nlmsg_len)))
{
switch (rtattr->rta_type)
{
case IFLA_UNSPEC:
debug_printf(DEBUG_INT, "IFLA_UNSPEC event.\n");
break;
case IFLA_ADDRESS:
debug_printf(DEBUG_INT, "IFLA_ADDRESS event.\n");
break;
case IFLA_BROADCAST:
debug_printf(DEBUG_INT, "IFLA_BROADCAST event.\n");
break;
case IFLA_IFNAME:
// This is a non-wireless event. (Ignore it.)
debug_printf(DEBUG_INT, "IFLA_IFNAME event.\n");
break;
case IFLA_MTU:
debug_printf(DEBUG_INT, "IFLA_MTU event.\n");
break;
case IFLA_LINK:
debug_printf(DEBUG_INT, "IFLA_LINK event.\n");
break;
case IFLA_WIRELESS:
// This is a wireless event.
cardif_linux_rtnetlink_ifla_wireless(intdata, ifinfo->ifi_index,
((char *) rtattr)+rtalen,
rtattr->rta_len - rtalen);
break;
case IFLA_OPERSTATE:
cardif_linux_rtnetlink_ifla_operstate(intdata, ifinfo->ifi_index,
((char *) rtattr)+rtalen,
rtattr->rta_len - rtalen);
break;
default:
debug_printf(DEBUG_INT, "RTNetlink Event type %d\n",
rtattr->rta_type);
break;
}
rtlen = msg->nlmsg_len - nlmsg_len;
// Get the next attribute
rtattr = RTA_NEXT(rtattr, rtlen);
}
}
/***********************************************************
*
* Check the string that identifies the custom event that we got. And
* act on it.
*
***********************************************************/
void cardif_linux_rtnetlink_check_custom(context *intdata,
char *str)
{
if (!xsup_assert((intdata != NULL), "intdata != NULL", FALSE))
return;
if (!xsup_assert((str != NULL), "str != NULL", FALSE))
return;
if (strncmp(str, "MLME-MICHAELMICFAILURE.indication", 33) == 0)
{
intdata->statemachine->MICfailures++;
debug_printf(DEBUG_NORMAL, "MIC failure #%d!\n",
intdata->statemachine->MICfailures);
if (strstr(str, " unicast ") != NULL)
{
// The attempted attack was probably against the unicast key.
debug_printf(DEBUG_NORMAL, "MIC failure on unicast key!\n");
eapol_key_type254_request_new_key(intdata, 1);
intdata->send_size = 0;
} else {
// The attempted attack was probably against the group key.
debug_printf(DEBUG_NORMAL, "MIC failure on group key!\n");
eapol_key_type254_request_new_key(intdata, 0);
intdata->send_size = 0;
}
if (intdata->statemachine->MICfailures >= 2)
{
// The WPA/802.11i standard requires we assert countermeasures
// for 60 seconds.
if (timer_check_existing(intdata, COUNTERMEASURE_TIMER))
{
debug_printf(DEBUG_NORMAL, "For some reason, we already have "
"a countermeasure timer in the queue! Resetting "
"the timer!\n");
timer_reset_timer_count(intdata, COUNTERMEASURE_TIMER,
MIC_COUNTERMEASURE_TIMEOUT);
} else {
debug_printf(DEBUG_NORMAL, "Enabling MIC countermeasures!\n");
timer_add_timer(intdata, COUNTERMEASURE_TIMER,
MIC_COUNTERMEASURE_TIMEOUT,
NULL, &mic_disable_countermeasures);
}
cardif_countermeasures(intdata, TRUE);
}
}
}
/***********************************************************
*
* Check to see if we have become disassociated before the rekey_prob_timer
* (found in profile.h) reaches 0. If we have, it may indicate that we
* have a card driver that resets the card on a key set. This should only be
* a problem with WEP and older card drivers.
*
***********************************************************/
void cardif_linux_rtnetlink_check_key_prob(context *idata)
{
struct config_globals *globals = NULL;
if (!xsup_assert((idata != NULL), "idata != NULL", FALSE))
return;
globals = config_get_globals();
if (!xsup_assert((globals != NULL), "globals != NULL", FALSE))
return;
if (timer_check_existing(idata, REKEY_PROB_TIMER))
{
if (!TEST_FLAG(globals->flags, CONFIG_GLOBALS_NO_FRIENDLY_WARNINGS))
{
debug_printf(DEBUG_NORMAL, "** WARNING! ** You were disassocated "
"within a short time of setting a key!\nThis usually "
"means there is a problem with the card driver.\n"
"Please e-mail the developers for more information on "
"what this means. Be sure to include the type of card, "
"driver in use, and driver version number.\n");
}
}
}
/***********************************************************
*
* Process operstate events.
*
***********************************************************/
void cardif_linux_rtnetlink_ifla_operstate(context *idata,
int ifindex, char *data, int len)
{
if (!xsup_assert((idata != NULL), "idata != NULL", FALSE))
return;
if (!xsup_assert((data != NULL), "data != NULL", FALSE))
return;
debug_printf(DEBUG_INT, "Got a netlink OPERSTATE event!\n");
debug_printf(DEBUG_INT, "OPERSTATE event on interface %d\n", ifindex);
debug_printf(DEBUG_INT, "Event dump (%d) : \n", len);
debug_hex_dump(DEBUG_INT, data, len);
switch(data[0])
{
case XIF_OPER_UNKNOWN:
debug_printf(DEBUG_INT, "Interface is in unknown state.\n");
break;
case XIF_OPER_NOTPRESENT:
debug_printf(DEBUG_INT, "Interface is not present.\n");
break;
case XIF_OPER_DOWN:
debug_printf(DEBUG_INT, "Interface is down.\n");
break;
case XIF_OPER_LOWERLAYERDOWN:
debug_printf(DEBUG_INT, "Interface lower layer is down.\n");
break;
case XIF_OPER_DORMANT:
debug_printf(DEBUG_INT, "Interface is dormant.\n");
break;
case XIF_OPER_UP:
debug_printf(DEBUG_INT, "Interface is up.\n");
break;
default:
debug_printf(DEBUG_INT, "Unknown interface state %d.\n", data[0]);
break;
}
}
/***********************************************************
*
* Process wireless events.
*
***********************************************************/
void cardif_linux_rtnetlink_ifla_wireless(context *idata,
int ifindex, char *data, int len)
{
struct iw_event iwe;
struct config_globals *globals = NULL;
struct stream_descr stream;
wireless_ctx *wctx = NULL;
int intIndex = 0;
int ret = 0;
if (!xsup_assert((idata != NULL), "idata != NULL", FALSE))
return;
if (!xsup_assert((data != NULL), "data != NULL", FALSE))
return;
if (!xsup_assert((idata->intTypeData != NULL), "idata->intTypeData != NULL",
FALSE))
return;
wctx = (wireless_ctx *)idata->intTypeData;
if ((data == NULL) || (len == 0))
{
debug_printf(DEBUG_NORMAL, "No data available in event!\n");
return;
}
globals = config_get_globals();
if (!xsup_assert((globals != NULL), "globals != NULL", FALSE))
return;
iw_init_event_stream(&stream, data, len);
do
{
#ifdef NEW_IWLIB
ret = iw_extract_event_stream(&stream, &iwe,
cardif_linux_rtnetlink_get_we_ver(idata));
#else
ret = iw_extract_event_stream(&stream, &iwe);
#endif
if (ret <= 0) return;
intIndex = if_nametoindex(idata->intName);
if ((ifindex != intIndex) &&
(!(TEST_FLAG(wctx->flags, WIRELESS_ONEDOWN))))
{
debug_printf(DEBUG_INT, "Got a wireless event! Interface index is %d, "
"we are using index %d!\n", ifindex, intIndex);
debug_printf(DEBUG_INT, "Ignoring!\n");
return;
}
if (TEST_FLAG(idata->flags, WIRELESS_ONEDOWN))
{
if ((ifindex < (intIndex - 1)) || (ifindex > (intIndex)))
{
debug_printf(DEBUG_INT, "Got a wireless event! Interface index is "
"%d, we are using indexes %d & %d!\n", ifindex,
intIndex-1, intIndex);
return;
}
}
// Process the event.
cardif_linux_rtnetlink_process_token(idata, &iwe);
} while (ret > 0);
}
/*************************************************************************
*
* Manually check and see if we have scan data to return. This is needed
* for devices that don't return scan complete events.
*
*************************************************************************/
uint8_t cardif_linux_rtnetlink_scancheck(context *ctx)
{
wireless_ctx *wctx;
if (!xsup_assert((ctx != NULL), "ctx != NULL", FALSE))
return 0;
if (!xsup_assert((ctx->intTypeData != NULL), "ctx->intTypeData != NULL",
FALSE))
return 0;
wctx = (wireless_ctx *)ctx->intTypeData;
if (ctx->intType == ETH_802_11_INT)
{
if (TEST_FLAG(wctx->flags, WIRELESS_SCANNING))
{
// It is okay to set a socket of -1 to rtnetlink_check_event. It
// uses an internal variable to keep track of it's socket anyway.
if (cardif_linux_rtnetlink_check_event(ctx, -1) != XDATA)
{
debug_printf(DEBUG_INT, "Waiting for SSID information...\n");
}
else
{
// We got data, and canceled our timer, so let the caller know.
#warning Update caller to use the proper value!
return 0xff;
}
}
}
return 0;
}
/*************************************************************************
*
* Add an attribute to our packet that we are going to send to the kernel.
*
*************************************************************************/
int cardif_linux_rtnetlink_add_attr(int type, struct nlmsghdr *nldr,
int bufsize, uint8_t *data, int attrlen)
{
struct rtattr *rtattr = NULL;
int len = 0;
// Determine the total length of the message.
len = RTA_LENGTH(attrlen);
if (NLMSG_ALIGN(nldr->nlmsg_len)+len > bufsize)
{
debug_printf(DEBUG_NORMAL, "Not enough buffer space to create netlink "
"request. Buffer size is %d, but required buffer size "
"is %d.\n", bufsize, NLMSG_ALIGN(nldr->nlmsg_len));
return -1;
}
rtattr = (struct rtattr *)(((char *)nldr) + NLMSG_ALIGN(nldr->nlmsg_len));
rtattr->rta_type = type;
rtattr->rta_len = len;
memcpy(RTA_DATA(rtattr), data, attrlen);
// Update our length to account for everything.
nldr->nlmsg_len = NLMSG_ALIGN(nldr->nlmsg_len) + len;
return 0;
}
/*************************************************************************
*
* On init, we need to tell the OS to put interfaces that are "UP" in to
* dormant mode. See http://www.flamewarmaster.de/software/operstates.txt
* for information on how this should all work.
*
*************************************************************************/
void cardif_linux_rtnetlink_set_linkmode(context *ctx, uint8_t newstate)
{
struct {
struct nlmsghdr nlmsg;
struct ifinfomsg ifi;
uint8_t data[sizeof(struct rtattr)+1];
} state;
static int seq;
debug_printf(DEBUG_INT, "Setting Linkmode to %d.\n", newstate);
memset(&state, 0x00, sizeof(state));
state.nlmsg.nlmsg_type = RTM_SETLINK;
state.nlmsg.nlmsg_seq = ++seq;
state.nlmsg.nlmsg_flags = NLM_F_REQUEST;
state.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
state.ifi.ifi_family = AF_UNSPEC;
state.ifi.ifi_index = if_nametoindex(ctx->intName);
if (cardif_linux_rtnetlink_add_attr(IFLA_LINKMODE, &state.nlmsg,
sizeof(state), &newstate, 1) != 0)
{
// Couldn't do anything.
return;
}
// Otherwise, send the packet.
send(rtnl_sock, (void *)&state, sizeof(state), 0);
}
/*************************************************************************
*
* Send an RTNETLINK message that indicates that the interface is now
* fully up. This will allow things such as DHCP to happen.
*
* See http://www.flamewarmaster.de/software/operstates.txt for information
* on how this should all work.
*
*************************************************************************/
void cardif_linux_rtnetlink_set_operstate(context *ctx, uint8_t newstate)
{
struct operstaterequest {
struct nlmsghdr nlmsg;
struct ifinfomsg ifi;
uint8_t data[sizeof(struct rtattr)+1];
};
static uint32_t seq;
struct operstaterequest opstate;
debug_printf(DEBUG_INT, "Setting operstate to %d\n", newstate);
memset(&opstate, 0x00, sizeof(opstate));
opstate.nlmsg.nlmsg_type = RTM_SETLINK;
opstate.nlmsg.nlmsg_seq = ++seq;
opstate.nlmsg.nlmsg_flags = NLM_F_REQUEST;
opstate.nlmsg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
opstate.ifi.ifi_family = AF_UNSPEC;
opstate.ifi.ifi_index = if_nametoindex(ctx->intName);
if (cardif_linux_rtnetlink_add_attr(IFLA_OPERSTATE, &opstate.nlmsg,
sizeof(opstate), &newstate, 1) != 0)
{
// Couldn't do anything.
return;
}
// Otherwise, send the packet.
send(rtnl_sock, (void *)&opstate, sizeof(opstate), 0);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -