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

📄 ieee802_1x.c

📁 802.1x 源码,基于linux平台开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *
 * 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 + -