📄 ieee802_1x.c
字号:
/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
Module Name:
ieee802_1x.c
Revision History:
Who When What
-------- ---------- ----------------------------------------------
Jan, Lee Dec --2003 modified
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>
#include "rt61apd.h"
#include "ieee802_1x.h"
#include "radius.h"
#include "radius_client.h"
#include "eapol_sm.h"
#include "md5.h"
#include "eloop.h"
#include "sta_info.h"
#include "mac2port.h"
extern int switch_cli_pipe_write(char *command);
static void ieee802_1x_send(rtapd *rtapd, struct sta_info *sta, u8 type, u8 *data, size_t datalen)
{
char *buf;
struct ieee8023_hdr *hdr3;
struct ieee802_1x_hdr *xhdr;
size_t len;
u8 *pos;
int lPort;
len = sizeof(*hdr3) + 2+ sizeof(*xhdr) +datalen;
buf = (char *) malloc(len);
if (buf == NULL)
{
DBGPRINT(RT_DEBUG_ERROR,"malloc() failed for ieee802_1x_send(len=%d)\n", len);
return;
}
DBGPRINT(RT_DEBUG_INFO,"Send to Sta(ra%d) with Identifier %d\n",sta->ApIdx,*(data+1));
memset(buf, 0, len);
hdr3 = (struct ieee8023_hdr *) buf;
memcpy(hdr3->dAddr, sta->addr, ETH_ALEN);
memcpy(hdr3->sAddr, rtapd->own_addr[sta->ApIdx], ETH_ALEN);
if (sta->ethertype == ETH_P_PRE_AUTH)
(hdr3->eth_type) = htons(ETH_P_PRE_AUTH);
else
(hdr3->eth_type) = htons(ETH_P_PAE);
pos = (u8 *) (hdr3 + 1);
xhdr = (struct ieee802_1x_hdr *) pos;
if (sta->ethertype == ETH_P_PRE_AUTH)
xhdr->version = EAPOL_VERSION_2;
else
xhdr->version = EAPOL_VERSION;
xhdr->type = type;
xhdr->length = htons(datalen);
if (datalen > 0 && data != NULL)
memcpy(pos + LENGTH_8021X_HDR, data, datalen);
lPort = Mac2Port_FindPortByMac(hdr3->dAddr);
if(lPort != -1)
{
if (sta->ethertype == ETH_P_PAE)
{
//fprintf(stderr, "tx packet port=%d,sta=%d\n", lPort,sta);
if (RT_ioctl(rtapd, RTPRIV_IOCTL_RADIUS_DATA, buf, len, lPort)<0)
DBGPRINT(RT_DEBUG_ERROR,"ioctl failed for ieee802_1x_send(len=%d)\n", len);
}
}
free(buf);
}
void ieee802_1x_set_sta_port_status(int lBlockFlag, int lPort)
{
char cCmdBuf[256];
memset(cCmdBuf, 0, sizeof(cCmdBuf));
if(lBlockFlag == TRUE)
{
sprintf(cCmdBuf, "auth block pbm=fe%d\n",lPort);
}
else
{
sprintf(cCmdBuf, "auth unblock pbm=fe%d\n",lPort);
}
switch_cli_pipe_write(cCmdBuf);
}
void ieee802_1x_set_sta_authorized( int authorized)
{
switch(authorized)
{
case 0:
DBGPRINT(RT_DEBUG_TRACE,"IEEE802_1X_Set_Sta_Authorized FAILED \n");
// Ap_free_sta(rtapd, sta);
break;
case 1:
DBGPRINT(RT_DEBUG_TRACE,"IEEE802_1X_Set_Sta_Authorized SUCCESSED \n");
break;
}
}
void ieee802_1x_request_identity(rtapd *rtapd, struct sta_info *sta, u8 id)
{
char *buf;
struct eap_hdr *eap;
int tlen;
u8 *pos;
ieee802_1x_new_auth_session(rtapd, sta);
tlen = sizeof(*eap) + 1 ;
buf = (char *) malloc(tlen);
if (buf == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, "Could not allocate memory for identity request\n");
return;
}
memset(buf, 0, tlen);
eap = (struct eap_hdr *) buf;
eap->code = EAP_CODE_REQUEST;
eap->identifier = id;
eap->length = htons(tlen);
pos = (u8 *) (eap + 1);
*pos++ = EAP_TYPE_IDENTITY;
DBGPRINT(RT_DEBUG_TRACE, "IEEE802_1X_Request_Identity %d bytes: \n",tlen);
ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET, buf, tlen);
free(buf);
}
void ieee802_1x_tx_canned_eap(rtapd *rtapd, struct sta_info *sta, u8 id, int success)
{
struct eap_hdr eap;
memset(&eap, 0, sizeof(eap));
eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
eap.identifier = id;
eap.length = htons(sizeof(eap));
DBGPRINT(RT_DEBUG_TRACE,"Send to Sta with Identifier %d\n",id);
ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET, (u8 *) &eap, sizeof(eap));
}
void ieee802_1x_tx_req(rtapd *rtapd, struct sta_info *sta, u8 id)
{
struct eap_hdr *eap;
if (sta->last_eap_radius == NULL)
{
DBGPRINT(RT_DEBUG_ERROR,"Error: TxReq called for station " MACSTR ", but there "
"is no EAP request from the authentication server\n", MAC2STR(sta->addr));
return;
}
eap = (struct eap_hdr *) sta->last_eap_radius;
if (eap->identifier != id)
{
DBGPRINT(RT_DEBUG_WARN,"IEEE 802.1X: TxReq(%d) - changing id from %d\n", id, eap->identifier);
eap->identifier = id;
}
DBGPRINT(RT_DEBUG_TRACE, "* ieee802_1x_tx_req call ieee802_1x_send id=%d\n",id);
ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET, sta->last_eap_radius, sta->last_eap_radius_len);
}
#if 0
static void ieee802_1x_tx_key_one(rtapd *hapd, struct sta_info *sta,
int index, int broadcast,
u8 *key_data, size_t key_len)
{
u8 *buf, *ekey;
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
struct timeval now;
size_t len, ekey_len;
u32 ntp_hi, ntp_lo, sec, usec;
len = sizeof(*key) + key_len;
buf = malloc(sizeof(*hdr) + len);
if (buf == NULL)
return;
memset(buf, 0, sizeof(*hdr) + len);
hdr = (struct ieee802_1x_hdr *) buf;
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
key->type = EAPOL_KEY_TYPE_RC4;
key->key_length = htons(key_len);
/* Set the NTP timestamp as the replay counter */
gettimeofday(&now, NULL);
sec = now.tv_sec;
usec = now.tv_usec;
#define JAN_1970 0x83aa7e80UL /* seconds from 1900 to 1970 */
ntp_hi = htonl(sec + JAN_1970);
/* approximation of 2^32/1000000 * usec */
ntp_lo = htonl(4295 * usec - (usec >> 5) - (usec >> 9));
memcpy(&key->replay_counter[0], &ntp_hi, sizeof(u32));
memcpy(&key->replay_counter[4], &ntp_lo, sizeof(u32));
if (hostapd_get_rand(key->key_iv, sizeof(key->key_iv)))
{
DBGPRINT(RT_DEBUG_ERROR, "Could not get random numbers\n");
free(buf);
return;
}
key->key_index = index | (broadcast ? 0 : BIT(7));
// if (hapd->conf->eapol_key_index_workaround) {
/* According to some information, WinXP Supplicant seems to
* interrept bit7 as an indication whether the key is to be
* activated, so make it possible to enable workaround that
* sets this bit for all keys. */
// key->key_index |= BIT(7);
// }
DBGPRINT(RT_DEBUG_TRACE, "key_index= %d key_length= %d \n",index, key_len);
/* Key is encrypted using "Key-IV + sta->eapol_key_crypt" as the
* RC4-key */
memcpy((u8 *) (key + 1), key_data, key_len);
ekey_len = sizeof(key->key_iv) + sta->eapol_key_crypt_len;
ekey = malloc(ekey_len);
if (ekey == NULL)
{
DBGPRINT(RT_DEBUG_TRACE,"Could not encrypt key\n");
free(buf);
return;
}
memcpy(ekey, key->key_iv, sizeof(key->key_iv));
memcpy(ekey + sizeof(key->key_iv), sta->eapol_key_crypt, sta->eapol_key_crypt_len);
rc4((u8 *) (key + 1), key_len, ekey, ekey_len);
free(ekey);
/* This header is needed here for HMAC-MD5, but it will be regenerated in ieee802_1x_send() */
hdr->version = EAPOL_VERSION;
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = htons(len);
hmac_md5(sta->eapol_key_sign, sta->eapol_key_sign_len, buf, sizeof(*hdr) + len, key->key_signature);
ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
free(buf);
}
void ieee802_1x_tx_key(rtapd *rtapd, struct sta_info *sta, u8 id)
{
NDIS_802_11_KEY WepKey, *pWepKey;
if (!sta->eapol_key_sign || !sta->eapol_key_crypt)
return;
memset(&WepKey, 0, sizeof(NDIS_802_11_KEY));
pWepKey = &WepKey;
ieee802_1x_tx_key_one(rtapd, sta, 0, 1, rtapd->conf->IEEE8021X_ikey, rtapd->conf->individual_wep_key_len);
WepKey.KeyIndex = 0x80000000 | 0;
WepKey.KeyLength = rtapd->conf->individual_wep_key_len;
memcpy(WepKey.KeyMaterial, rtapd->conf->IEEE8021X_ikey, rtapd->conf->individual_wep_key_len);
memcpy(WepKey.addr, sta->addr, 6);
// WPA2(pre-auth)
if (sta->ethertype== ETH_P_PRE_AUTH)
{
if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_PMKID_CACHE, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), 0))
{
DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
return;
}
}
else
{
if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_WPA_KEY, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), sta->ApIdx))
{
DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_WPA_KEY\n");
return;
}
}
ieee802_1x_tx_key_one(rtapd, sta, 3, 0, rtapd->conf->IEEE8021X_ikey, rtapd->conf->individual_wep_key_len);
WepKey.KeyIndex = 0x80000000 | 3;
WepKey.KeyLength = rtapd->conf->individual_wep_key_len;
memcpy(WepKey.KeyMaterial, rtapd->conf->IEEE8021X_ikey, rtapd->conf->individual_wep_key_len);
memcpy(WepKey.addr, sta->addr, 6);
// WPA2(pre-auth)
if (sta->ethertype == ETH_P_PRE_AUTH)
{
if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_PMKID_CACHE, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), 0))
{
DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
return;
}
}
else
{
if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_WPA_KEY, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), sta->ApIdx))
{
DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_WPA_KEY\n");
return;
}
}
}
#endif
static void ieee802_1x_encapsulate_radius(rtapd *rtapd, struct sta_info *sta, u8 *eap, size_t len)
{
struct radius_msg *msg;
char buf[128];
sta->radius_identifier = Radius_client_get_id(rtapd);
msg = Radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, sta->radius_identifier);
if (msg == NULL)
{
DBGPRINT(RT_DEBUG_ERROR, "Could not create net RADIUS packet\n");
return;
}
Radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(sta));
if (sta->identity && !Radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, sta->identity, sta->identity_len))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add User-Name\n");
goto fail;
}
// apd->conf->own_ip_addr is filled according to configuration file
if (!Radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &rtapd->conf->own_ip_addr, 4))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-IP-Address\n");
goto fail;
}
if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-Port\n");
goto fail;
}
snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(rtapd->own_addr[sta->ApIdx]));
if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, buf, strlen(buf)))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add Called-Station-Id\n");
goto fail;
}
snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(sta->addr));
if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, buf, strlen(buf)))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add Calling-Station-Id\n");
goto fail;
}
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
*/
if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1500))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add Framed-MTU\n");
goto fail;
}
if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_XDSL))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-Port-Type\n");
goto fail;
}
snprintf(buf, sizeof(buf), "CONNECT SUMINET-SH VMU21X0");
if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, buf, strlen(buf)))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add Connect-Info\n");
goto fail;
}
if (eap && !Radius_msg_add_eap(msg, eap, len))
{
DBGPRINT(RT_DEBUG_ERROR,"Could not add EAP-Message\n");
goto fail;
}
/* State attribute must be copied if and only if this packet is
* Access-Request reply to the previous Access-Challenge */
if (sta->last_recv_radius && sta->last_recv_radius->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE)
{
int res = Radius_msg_copy_attr(msg, sta->last_recv_radius, RADIUS_ATTR_STATE);
if (res < 0)
{
DBGPRINT(RT_DEBUG_ERROR,"Could not copy State attribute from previous Access-Challenge\n");
goto fail;
}
}
//fprintf(stderr, "Radius Send id=%d ,sta=%d\n",msg->hdr->identifier,sta);
Radius_client_send(rtapd, msg, RADIUS_AUTH);
return;
fail:
Radius_msg_free(msg);
free(msg);
}
static void handle_eap_response(struct sta_info *sta, struct eap_hdr *eap, u8 *data, size_t len)
{
u8 type;
//fprintf(stderr, " handle_eap_response\n");
assert(sta->eapol_sm != NULL);
if (eap->identifier != sta->eapol_sm->currentId)
{
DBGPRINT(RT_DEBUG_INFO,"EAP Identifier of the Response-Identity from " MACSTR
" does not match (was %d, expected %d)\n",
MAC2STR(sta->addr), eap->identifier,
sta->eapol_sm->currentId);
// didn't check identifier.. reasonable ?
return;
}
if (len < 1)
{
DBGPRINT(RT_DEBUG_WARN,"too short response data\n");
return;
}
if (sta->last_eap_supp != NULL)
free(sta->last_eap_supp);
sta->last_eap_supp_len = sizeof(*eap) + len;
sta->last_eap_supp = (u8 *) malloc(sta->last_eap_supp_len);
if (sta->last_eap_supp == NULL)
{
DBGPRINT(RT_DEBUG_ERROR,"Could not alloc memory for last EAP Response\n");
return;
}
memcpy(sta->last_eap_supp, eap, sizeof(*eap));
memcpy(sta->last_eap_supp + sizeof(*eap), data, len);
type = data[0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -