网卡mac地址

来源:互联网 发布:淘宝劲舞团情侣衣服 编辑:程序博客网 时间:2024/05/16 12:02

网卡MAC地址

 

一、MAC地址介绍

 

网卡MAC地址,被称为物理地址、硬件地址,长度是48比特(6字节),分为前24位和后24

24位叫做组织唯一标志符(Organizationally Unique Identifier,即OUI),是由IEEE的注册管理机构给不同厂家分配的代码,区分了不同的厂家。

24位是由厂家自己分配的,称为扩展标识符。同一个厂家生产的网卡中MAC地址后24位是不同的。

网卡MAC数据链路层,一个主机会有一个MAC地址,而每个网络位置会有一个专属于它的IP地址

MAC地址一般是厂商写在设备里面。

有些产品固定一个MAC,这样用户同一个局域网多台相同mac地址设备会导致通信出现问题这样就必须靠自己来随机生成MAC地址。

 

二、linux平台下usb网卡MAC地址随机生成方法;

在网卡驱动里面probe时。

memcpy (net->dev_addr, node_id, sizeof node_id);

 

static int __init usbnet_init(void)

{

/* compiler should optimize this out */

BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb)

< sizeof (struct skb_data));

 

random_ether_addr(node_id);

return 0;

}

 

/**

 * random_ether_addr - Generate software assigned random Ethernet address

 * @addr: Pointer to a six-byte array containing the Ethernet address

 *

 * Generate a random Ethernet address (MAC) that is not multicast

 * and has the local assigned bit set.

 */

static inline void random_ether_addr(u8 *addr)

{

get_random_bytes (addr, ETH_ALEN);

addr [0] &= 0xfe; /* clear multicast bit */

addr [0] |= 0x02; /* set local assignment bit (IEEE802) */

}

 

关于IEEE802 MAC地址的须知:

 IEEE802 LAN6字节MAC地址是目前广泛使用的LAN物理地址。IEEE802规定LAN地址字段的第一个字节的最低位表示I/GIndividual /Group)比特,即单地址/组地址比特。当它为“0”时,表示它代表一个单播地址,而这个位是“1”时,表示它代表一个组地址。
IEEE802规定LAN地址字段的第一个字节的最低第二位表示G/LGlobe/Local)比特,即全球/本地比特。当这个比特为“0”时,表 示全球管理,物理地址是由全球局域网地址的法定管理机构统一管理,全球管理地址在全球范围内不会发生地址冲突。当这个比特为“1”时,就是本地管理,局域 网管理员可以任意分配局部管理的网络上的地址,只要在自己网络中地址唯一不产生冲突即可,对外则没有意义,局部管理很少使用。
  在6个字节的其他46个比特用来标识一个特定的MAC地址,46位的地址空间可表示约70万亿个地址,可以保证全球地址的唯一性。   

 

 

#define  ETH_ALEN 6

 

driver/char/random.c

/*

 * This function is the exported kernel interface.  It returns some

 * number of good random numbers, suitable for seeding TCP sequence

 * numbers, etc.

 */

void get_random_bytes(void *buf, int nbytes)

{

extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);

}

 

static ssize_t extract_entropy(struct entropy_store *r, void *buf,

       size_t nbytes, int min, int reserved)

{

ssize_t ret = 0, i;

__u8 tmp[EXTRACT_SIZE];

unsigned long flags;

 

xfer_secondary_pool(r, nbytes);

nbytes = accouextract_entropynt(r, nbytes, min, reserved);

 

while (nbytes) {

extract_buf(r, tmp);

 

if (fips_enabled) {

spin_lock_irqsave(&r->lock, flags);

if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))

panic("Hardware RNG duplicated output!\n");

memcpy(r->last_data, tmp, EXTRACT_SIZE);

spin_unlock_irqrestore(&r->lock, flags);

}

i = min_t(int, nbytes, EXTRACT_SIZE);

memcpy(buf, tmp, i);

nbytes -= i;

buf += i;

ret += i;

}

 

/* Wipe data just returned from memory */

memset(tmp, 0, sizeof(tmp));

 

return ret;

}

 

 

 

/*

 * This utility inline function is responsible for transfering entropy

 * from the primary pool to the secondary extraction pool. We make

 * sure we pull enough for a 'catastrophic reseed'.

 */

static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)

{

__u32 tmp[OUTPUT_POOL_WORDS];

 

if (r->pull && r->entropy_count < nbytes * 8 &&

    r->entropy_count < r->poolinfo->POOLBITS) {

/* If we're limited, always leave two wakeup worth's BITS */

int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;

int bytes = nbytes;

 

/* pull at least as many as BYTES as wakeup BITS */

bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);

/* but never more than the buffer size */

bytes = min_t(int, bytes, sizeof(tmp));

 

DEBUG_ENT("going to reseed %s with %d bits "

  "(%d of %d requested)\n",

  r->name, bytes * 8, nbytes * 8, r->entropy_count);

 

bytes = extract_entropy(r->pull, tmp, bytes,

random_read_wakeup_thresh / 8, rsvd);

mix_pool_bytes(r, tmp, bytes);

credit_entropy_bits(r, bytes*8);

}

}

 

/*

 * These functions extracts randomness from the "entropy pool", and

 * returns it in a buffer.

 *

 * The min parameter specifies the minimum amount we can pull before

 * failing to avoid races that defeat catastrophic reseeding while the

 * reserved parameter indicates how much entropy we must leave in the

 * pool after each pull to avoid starving other readers.

 *

 * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words.

 */

 

static size_t account(struct entropy_store *r, size_t nbytes, int min,

      int reserved)

{

unsigned long flags;

 

/* Hold lock while accounting */

spin_lock_irqsave(&r->lock, flags);

 

BUG_ON(r->entropy_count > r->poolinfo->POOLBITS);

DEBUG_ENT("trying to extract %d bits from %s\n",

  nbytes * 8, r->name);

 

/* Can we pull enough? */

if (r->entropy_count / 8 < min + reserved) {

nbytes = 0;

} else {

/* If limited, never pull more than available */

if (r->limit && nbytes + reserved >= r->entropy_count / 8)

nbytes = r->entropy_count/8 - reserved;

 

if (r->entropy_count / 8 >= nbytes + reserved)

r->entropy_count -= nbytes*8;

else

r->entropy_count = reserved;

 

if (r->entropy_count < random_write_wakeup_thresh) {

wake_up_interruptible(&random_write_wait);

kill_fasync(&fasync, SIGIO, POLL_OUT);

}

}

 

DEBUG_ENT("debiting %d entropy credits from %s%s\n",

  nbytes * 8, r->name, r->limit ? "" : " (unlimited)");

 

spin_unlock_irqrestore(&r->lock, flags);

 

return nbytes;

}

 

static void extract_buf(struct entropy_store *r, __u8 *out)

{

int i;

__u32 hash[5], workspace[SHA_WORKSPACE_WORDS];

__u8 extract[64];

 

/* Generate a hash across the pool, 16 words (512 bits) at a time */

sha_init(hash);

for (i = 0; i < r->poolinfo->poolwords; i += 16)

sha_transform(hash, (__u8 *)(r->pool + i), workspace);

 

/*

 * We mix the hash back into the pool to prevent backtracking

 * attacks (where the attacker knows the state of the pool

 * plus the current outputs, and attempts to find previous

 * ouputs), unless the hash function can be inverted. By

 * mixing at least a SHA1 worth of hash data back, we make

 * brute-forcing the feedback as hard as brute-forcing the

 * hash.

 */

mix_pool_bytes_extract(r, hash, sizeof(hash), extract);

 

/*

 * To avoid duplicates, we atomically extract a portion of the

 * pool while mixing, and hash one final time.

 */

sha_transform(hash, extract, workspace);

memset(extract, 0, sizeof(extract));

memset(workspace, 0, sizeof(workspace));

 

/*

 * In case the hash function has some recognizable output

 * pattern, we fold it in half. Thus, we always feed back

 * twice as much data as we output.

 */

hash[0] ^= hash[3];

hash[1] ^= hash[4];

hash[2] ^= rol32(hash[2], 16);

memcpy(out, hash, EXTRACT_SIZE);

memset(hash, 0, sizeof(hash));

}

 

 

此段关于熵(entropy)的理解转自https://my.oschina.net/lieefu/blog/549455

Linux内核采用熵来描述数据的随机性。

熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。在信息学中,熵被用来表征一个符号或系统的不确定性,熵越大,表明系统所含有用信息量越少,不确定度越大。 
计算机本身是可预测的系统,因此,用计算机算法不可能产生真正的随机数。但是机器的环境中充满了各种各样的噪声,如硬件设备发生中断的时间,用户点击鼠标的时间间隔等是完全随机的,事先无法预测。Linux内核实现的随机数产生器正是利用系统中的这些随机噪声来产生高质量随机数序列。 

内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。理论上,熵池中的数据是完全随机的,可以实现产生真随机数序列。为跟踪熵池中数据的随机性,内核在将数据加入池的时候将估算数据的随机性,这个过程称作熵估算。熵估算值描述池中包含的随机数位数,其值越大表示池中数据的随机性越好。

内核提供了两个字符设备: /dev/random/dev/urandom,其read函数(random_read()urandom_read())用于向用户模式程序输出随机数序列。上层应用程序可以通过read系统调用从它们获取随机数序列。相对于/dev/urandom接口,/dev/random输出的随机数序列质量更高,适合于高强度的加密算法。/dev/urandom总是返回所请求的随机数序列,无论熵池的熵估算值是否为零;而/dev/random则只返回熵估算值所允许的最长的随机数序列,当熵估算值为零时,请求将被阻塞直到熵估算值增大到一定域值。
上述输出接口最终均是通过调用 extract_entropy()函数输出随机数序列。Extract_entropy()函数使用SHAMD5算法散列(Hash)熵池,将散列后的结果作为随机数序列输出给用户使用,这样避免了直接访问熵池中的内容。由于从SHAMD5算法散列的结果反推原始数据的可能性几乎为零,所以这种设计极大的提高了安全性。攻击者无法直接访问熵池,也无法根据过去的随机数序列预测将来的序列。
当系统启动的时候,由于启动过程是个确定的可预测的过程,这种情况下,熵池的熵值将非常小,导致产生的随机数序列质量下降,从而给攻击者破解的可能。为了克服系统启动过程的可预测性带来的影响,Linux操作系统在系统关机的时候保存当前熵池的内容,当系统下次启动的时候恢复上次关机时熵池的数据,这样就有效增加了熵池的熵估算值,避免了随机数序列质量的下降。

 

 

 

三、在应用层随机生成mac地址

linux下生成随机数设备/dev/urandom和/dev/random。

/dev/random读取随机数时,可能产生阻塞,随机性更高。第一烧写程序到板子里面,结果mac地址相同。

/dev/urandom读取随机数时,速度更快,能够满足要求。建议选择此设备产生随机数。

原创粉丝点击