我想了解如何将 MAC 地址转换为 IPv6 地址。
例如,
00:01:04:76:2A:5C
应该成为
FE80::0201:04FF:FE76:2A5C
请问我该如何进行转换? 我们假设本地机器没有随机参数的自动配置。
逐步转换从 MAC 地址(48 位)到 IPv6 地址(128 位):
Bash/zsh 功能(现在无需 bc 即可工作):
format_eui_64() {
local macaddr="$1"
printf "%02x%s" $(( 16#${macaddr:0:2} ^ 2#00000010 )) "${macaddr:2}" \
| sed -E -e 's/([0-9a-zA-Z]{2})*/0x\0|/g' \
| tr -d ':\n' \
| xargs -d '|' \
printf "%02x%02x:%02xff:fe%02x:%02x%02x"
}
我已经在 C 中工作了。欢迎提出建议。
#include <stdio.h>
#include <string.h>
int toogle_kth_bit(unsigned int n, int k) {
return (n ^ (1 << (k-1)));
}
/*
- take the mac address: 52:74:f2:b1:a8:7f
- throw ff:fe in the middle: 52:74:f2:ff:fe:b1:a8:7f
- reformat to IPv6 notation 5274:f2ff:feb1:a87f
- convert the first octet from hexadecimal to binary: 52 -> 01010010
- invert the bit at index 6 (counting from 0): 01010010 -> 01010000
- convert octet back to hexadecimal: 01010000 -> 50
- replace first octet with newly calculated one: 5074:f2ff:feb1:a87f
- prepend the link-local prefix: fe80::5074:f2ff:feb1:a87f
*/
void mac_to_ipv6_link_local(char* mac) {
char mac_c[128];
char mac_c_exp[128];
char ipv6[128];
char ipv6_link_local[128];
char delim[] = ":";
int count = 0;
// throw ff:fe in the middle
snprintf(mac_c, sizeof(mac_c), "%s", mac);
char *ptr = strtok(mac_c, delim);
while (ptr != NULL) {
count++;
if (count > 1) {
snprintf(mac_c_exp, sizeof(mac_c_exp), "%s:%s", mac_c_exp, ptr);
} else {
snprintf(mac_c_exp, sizeof(mac_c_exp), "%s%s", mac_c_exp, ptr);
}
if (count == 3) {
snprintf(mac_c_exp, sizeof(mac_c_exp), "%s:%s", mac_c_exp, "ff:fe");
}
ptr = strtok(NULL, delim);
}
// reformat to IPv6 notation
ptr = strtok(mac_c_exp, delim);
count = 0;
while (ptr != NULL) {
count++;
if (count % 2 != 0 && count > 1) {
snprintf(ipv6, sizeof(ipv6), "%s:%s", ipv6, ptr);
} else {
snprintf(ipv6, sizeof(ipv6), "%s%s", ipv6, ptr);
}
ptr = strtok(NULL, delim);
}
// convert the first octet from hexadecimal to binary
char hex[2] = {ipv6[0], ipv6[1]};
char inverted_hex[3];
unsigned int number = (unsigned int)strtol(hex, NULL, 16);
// invert the bit at index 6 (counting from 0)
unsigned int new_num = toogle_kth_bit(number, 2);
sprintf(inverted_hex, "%x", new_num);
// replace first octet with newly calculated one
ipv6[0] = inverted_hex[0];
ipv6[1] = inverted_hex[1];
// prepend the link-local prefix
sprintf(ipv6_link_local, "%s%s", "fe80::", ipv6);
printf("%s\n", ipv6_link_local);
}
int main() {
mac_to_ipv6_link_local("52:74:f2:b1:a8:7f");
return 0;
}
我的 C# 解决方案或转换:
using System;
using System.Text.RegularExpressions;
namespace mac2ipv6
{
class Program
{
static string mac = "52:74:f2:b1:a8:f7";
static void Main(string[] args)
{
// Remove ':' and '-' from input mac
string bare_mac = Regex.Replace(mac, "[:-]", String.Empty);
// Insert fffe in the middle
bare_mac = bare_mac.Insert(6, "fffe");
// XOR first octet with 00000010
int first_octet = Convert.ToInt32(bare_mac.Substring(0, 2), 16);
int mask = 2;
int new_first_octet= first_octet ^ mask;
string new_first_octet_hex = new_first_octet.ToString("X");
// Replace first octet
bare_mac = new_first_octet_hex + bare_mac.Substring(2);
// Prepend link local prefix and format ipv6
string ipv6 = ("fe80::" + Regex.Replace(bare_mac, ".{4}", "${0}:")).TrimEnd(':');
Console.WriteLine(ipv6);
Console.ReadKey();
}
}
}
Excel公式:
=CONCAT("fe80::",LOWER(DEC2HEX(BITXOR(HEX2DEC(LEFT(A1,2)),2),2)),MID(A1,4,5),"ff:fe",MID(A1,10,5),RIGHT(A1,2))
这是 Golang 上的解决方案:
func mac2ip(s string) (net.IP, error) {
mac, err := net.ParseMAC(s)
if err != nil {
return nil, err
}
// Invert the bit at the index 6 (counting from 0)
mac[0] ^= (1 << (2 - 1))
ip := []byte{
0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // prepend with fe80::
mac[0], mac[1], mac[2], 0xff, 0xfe, mac[3], mac[4], mac[5], // insert ff:fe in the middle
}
return ip, nil
}
完整版:https://gist.github.com/0xef53/cb1c5d7594683982ba41d303ac03e9a0
修复以“00”开头的 MAC 地址 字符串 new_first_octet_hex = new_first_octet.ToString("X2");
单元格“A1”中 MAC 地址的德语 Excel 公式:
=KLEIN(VERKETTEN("fe80::",KLEIN(DEZINHEX(BITXODER(HEXINDEZ(LINKS(A1,2)),2),2)),TEIL(A1,4,5),"ff:fe",TEIL(A1,10,5),RECHTS(A1,2)))
我在前面添加了“KLEIN”(德语中的“LOWER”),因为上面提到的原始公式没有为我将整个字符串转换为小写字母。