Преобразование из MAC в IPv6

Я хотел бы понять, как преобразовать MAC-адрес в IPv6. Например: 00:01:04:76:2A:5C Должно стать FE80::0201:04FF:FE76:2A5C

Может ли кто-нибудь уточнить преобразование, пожалуйста? Мы предполагаем автоматическую настройку без случайных параметров для локальной машины.


person Arkon    schedule 29.12.2014    source источник
comment
Взгляните на Измененный EUI-64.   -  person Rowland Shaw    schedule 29.12.2014


Ответы (6)


Пошаговое преобразование из MAC-адреса (48 бит) в IPv6-адрес (128 бит) :

  1. возьмем мак адрес: 52:74:f2:b1:a8:7f
  2. бросить ff:fe в середину: 52:74:f2:ff:fe:b1:a8:7f
  3. переформатировать в нотацию IPv6 5274:f2ff:feb1:a87f
  4. преобразовать первый октет из шестнадцатеричного в двоичный: 52 -> 01010010
  5. инвертировать бит с индексом 6 (считая с 0): 01010010 -> 01010000
  6. преобразовать октет обратно в шестнадцатеричный: 01010000 -> 50
  7. заменить первый октет новым вычисленным: 5074:f2ff:feb1:a87f
  8. добавьте префикс локальной ссылки: fe80::5074:f2ff:feb1:a87f
person helloflash    schedule 29.12.2014
comment
На самом деле бит U/L должен быть установлен, но в вашем примере этот бит очищается. Это объясняется в RFC 4291, Архитектура IP-адресации версии 6, Приложение A: Создание модифицированного EUI- 64 Идентификаторы интерфейса формата, которые показывают бит U/L, должны быть установлены в 1, чтобы показать локально полученный адрес EUI-64. - person Ron Maupin; 03.04.2020

Функция 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"
}
person cortex    schedule 22.01.2018
comment
Можете ли вы опубликовать вывод «bc -v»? Я получаю правильный результат в своей системе и пока не могу воспроизвести ваш вывод. - person cortex; 25.02.2018
comment
Ага, понятно! Проблема заключалась в том, что я использовал zsh, а не bash во всех тестовых случаях, и я не знал, что bash интерпретирует любой начальный нуль в арифметическом выражении как восьмеричное значение. Например, let "i = 010"; echo $i в bash возвращает 8, а то же выражение в zsh возвращает 10. - person cortex; 09.03.2018

Я получил это работает в 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;
}
person Endre Börcsök    schedule 16.04.2019

Мое решение С# или преобразование:

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();
        }
    }
}
person Martin Hess    schedule 02.04.2020
comment
Не XOR первый октет, а OR первый октет, потому что должен быть установлен бит U/L. Это объясняется в RFC 4291, Архитектура IP-адресации версии 6, Приложение A: Создание модифицированного EUI- 64 Идентификаторы интерфейса формата, которые показывают бит U/L, должны быть установлены на 1, чтобы показать локально полученный адрес EUI-64. - person Ron Maupin; 03.04.2020
comment
Я думаю, вы хотите вставить fffe в индекс 6, верно? - person AndrewF; 03.04.2020

Формула Эксель:

=CONCAT("fe80::",LOWER(DEC2HEX(BITXOR(HEX2DEC(LEFT(A1,2)),2),2)),MID(A1,4,5),"ff:fe",MID(A1,10,5),RIGHT(A1,2))
person Scrybe    schedule 31.03.2021

Вот решение на Голанге:

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

person Sergey Zhuravlev    schedule 07.04.2021