Jak wygenerować prawidłowy losowy adres MAC za pomocą powłoki bash

17

Jak mogę wygenerować prawidłowy losowy adres MAC za pomocą bash.

Pierwsza połowa adresu powinna zawsze pozostać taka sama

00-60-2F-xx-xx-xx

tylko wartość x powinna być generowana losowo?

NES
źródło
10
echo -n 00-60-2F; dd bs=1 count=3 if=/dev/random 2>/dev/null |hexdump -v -e '/1 "-%02X"'
artistoex,
1
@artistoex To było piękne ... Dlaczego nie opublikowałeś tego jako odpowiedzi?
bobmagoo,

Odpowiedzi:

18

Oto ryba.

Ten skrypt powłoki wygeneruje szukany ciąg losowy:

#!/bin/bash
hexchars="0123456789ABCDEF"
end=$( for i in {1..6} ; do echo -n ${hexchars:$(( $RANDOM % 16 )):1} ; done | sed -e 's/\(..\)/-\1/g' )
echo 00-60-2F$end

Właśnie miałem tutaj coś, co pokazało, jak uruchomić go z wiersza poleceń, ale po spojrzeniu na skomplikowane (ale uprzywilejowane) rozwiązanie Dennisa Williamsona widzę, że ludzie oczekują odpowiedzi, w której nie muszą wykonywać żadnej pracy sami.

deltaray
źródło
dzięki za uświadomienie sobie, że próbowałem zmusić go do nauki ryb zamiast karmienia łyżeczką rozwiązania
RobotHumans
1
Zawsze możesz wyjaśnić swoją odpowiedź, abyście oboje uczyli go, jak łowić ryby, oprócz tego, że tym razem ...
Jed Daniels,
Ten skrypt działa znacznie szybciej niż ten zaproponowany przez hbdgaf i nie generuje żadnego nieprawidłowego adresu MAC w pętli 1000 razy. Dzięki!
Bruno Finger
1
Twoje rozwiązanie działa i ma tylko 3 linie. Jestem sprzedany.
Richard Gomes,
17

W przeszłości robiłem to za pomocą:

echo 00-60-2F-$[RANDOM%10]$[RANDOM%10]-$[RANDOM%10]$[RANDOM%10]-$[RANDOM%10]$[RANDOM%10]

ale dzięki temu będą tylko w zakresie 0–9. Dla moich celów było to wystarczająco dobre.

Prawdopodobnie lepszym rozwiązaniem byłoby użycie printf:

printf '00-60-2F-%02X-%02X-%02X\n' $[RANDOM%256] $[RANDOM%256] $[RANDOM%256]

Oto jak to działa:

  • Program printf opiera się na funkcji C „printf”, która jako pierwszy parametr przyjmuje „ciąg formatu”, a następnie dodatkowe parametry wypełniają ciąg formatu.
  • % w ciągu formatu wprowadza „specyfikator formatu”, który może składać się z jednego lub więcej znaków informujących o tym, jak sformatować argumenty.
  • Zera wiodące (0) w specyfikatorze formatu oznacza, że ​​wynikowy wynik liczbowy powinien być uzupełniony zerami wiodącymi do określonej szerokości.
  • 2 mówi, że specyfikator powinien zostać wyświetlony przy szerokości dwóch znaków.
  • X kończy specyfikator i oznacza, że ​​należy go interpretować jako liczbę i wyświetlać w systemie szesnastkowym. Ponieważ litery są duże, litery af powinny być wielkie.
  • \ N jest znakiem nowej linii - printf interpretuje ukośnik odwrotny jako kod ucieczki, którego można używać do wyświetlania innych znaków, często trudnych znaków, takich jak znak nowej linii.
  • Pozostałe znaki w specyfikatorze formatu są drukowane dosłownie, w tym początkowe „00-06-2F-” i myślniki między specyfikatorami formatu.
  • Pozostałe argumenty to podstawienia zmiennych powłoki (oznaczone przez $) i zawierają wyrażenie matematyczne, które jest liczbą losową (RANDOM) modulo 256. Daje to losową liczbę od 0 do 255.
Sean Reifschneider
źródło
2
Jak słusznie zauważył użytkownik 58033 w odpowiedzi (która może już nie istnieć): %02Xdałby jedną wielką literę.
Arjan,
Ach, dobra racja. Odłożyłem, że w pierwotnym pytaniu podano przykład, używając wielkich liter. Dzięki za powitanie. :-)
Sean Reifschneider,
Dodatkowe +1, jeśli możesz wyjaśnić, co się dzieje i dlaczego Twoje rozwiązanie działa.
Jed Daniels,
Proszę bardzo, @Jed.
Sean Reifschneider,
17
  1. Wygeneruj odpowiednią wielkość int: http://tldp.org/LDP/abs/html/randomvar.html
  2. Konwertuj na hex tak: http://snipplr.com/view/2428/convert-from-int-to-hex/
  3. Dodaj myślniki między trzema losowo generowanymi fragmentami
#!/bin/bash
RANGE=255
#set integer ceiling

number=$RANDOM
numbera=$RANDOM
numberb=$RANDOM
#generate random numbers

let "number %= $RANGE"
let "numbera %= $RANGE"
let "numberb %= $RANGE"
#ensure they are less than ceiling

octets='00-60-2F'
#set mac stem

octeta=`echo "obase=16;$number" | bc`
octetb=`echo "obase=16;$numbera" | bc`
octetc=`echo "obase=16;$numberb" | bc`
#use a command line tool to change int to hex(bc is pretty standard)
#they're not really octets.  just sections.

macadd="${octets}-${octeta}-${octetb}-${octetc}"
#concatenate values and add dashes

echo $macadd
#echo result to screen
#note: does not generate a leading zero on single character sections.  easily remediedm but that's an exercise for you

Lub w python:

from random import randint
def gen_mac_char():
  return hex((randint(0,16))).split('x')[1]
def gen_mac_pair():
  return ''.join([gen_mac_char(), gen_mac_char()])
def gen_last_half_mac(stem):
  return '-'.join([stem, gen_mac_pair(), gen_mac_pair(), gen_mac_pair()])
print(gen_last_half_mac('00-60-2F'))

Zauważ, że wersja Pythona używa tylko 16-polowego pola do wygenerowania znaku szesnastkowego, więc nie musisz się martwić o zerowanie dopełniania - poprawiono podejście, aby odpowiedzieć na komentarz.

RobotHumans
źródło
Dodatkowe +1, jeśli podasz przykład każdego z nich (wiem, że uczysz go, jak łowić ryby, ale możesz dać mu elementy układanki do złożenia i wyjaśnić, jak / dlaczego działają).
Jed Daniels,
@Jed Daniels - gotowe i gotowe. podany kod.
RobotHumans
Ten kod generuje dla mnie kilka nieprawidłowych adresów MAC. Okręcając go 1000 razy mam kilka takich MAC 00-60-2F-8B-5-2C, 00-60-2F-A-71-97, 00-60-2F-82-F1-4.
Bruno Finger,
To było coś, co rzuciłem tam, odkąd OP nalegał na bash. Mówisz, że nie możesz wymyślić, jak uzupełnić pojedyncze cyfry zerą, prawda? @BrunoFinger
RobotHumans
Można łatwo przerobić, aby użyć 16 zamiast 255 i wygenerować zerowy symbol zastępczy. To tylko więcej linii ...
RobotHumans
12

Za pomocą standardowych narzędzi

# output in capitals
hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/random

lub

# output in lower case letters
echo 00-60-2f$(od -txC -An -N3 /dev/random|tr \  -)

może być najkrótszy ze wszystkich.

artistoex
źródło
Czy możesz opisać w swojej odpowiedzi, co dokładnie robi? Pomoże to również użyć go na inne sposoby!
Bruno Bieri,
7
#!/bin/bash
LC_CTYPE=C
MAC=00-60-2F
for i in {1..3}
do
    IFS= read -d '' -r -n 1 char < /dev/urandom
    MAC+=$(printf -- '-%02x\n' "'$char")
done
printf '%s\n' "$MAC"

Klucze do sposobu, w jaki to działa:

  • LC_CTYPE=C - zezwala na znaki> 0x7F
  • IFS=- wyłącza interpretację \t(tab), \n(nowa linia) i spacji
  • -d ''- pozwala na nowe linie
  • -rpozwala \(i prawie zawsze powinien być używany przez nawyk z read)
  • Specyfikator formatu -%02x\npowoduje, że wyjście jest dosłownym łącznikiem, po którym następuje dwucyfrowa liczba szesnastkowa, w razie potrzeby z wiodącym zerem. Nowa linia jest tutaj zbędna i można ją pominąć.
  • readDostaje jeden bajt ( -n 1) z /dev/urandomzakresu od 0 do 255 ( 00z FF).
  • Pojedynczy cudzysłów w ostatnim argumencie do printfpętli powoduje, że znak jest wyprowadzany jako jego wartość liczbowa („A” jest wyprowadzane jako „65”). Zobacz specyfikację POSIX,printf gdzie jest napisane:

    Jeżeli wiodącym znakiem jest pojedynczy cudzysłów lub podwójny cudzysłów, wartością jest wartość liczbowa w podstawowym zestawie znaków znaku następującego po pojedynczym cudzysłowie lub podwójnym cudzysłowie.

Wstrzymano do odwołania.
źródło
Wydaje się, że należy IFS= read …unikać składania 09 0a i 20 (zwykłe znaki IFS) do 00.
Chris Johnsen
@Chris: Przepraszam, wyjąłem kilka rzeczy podczas podwójnej kontroli i zapomniałem włożyć je z powrotem. Potrzebuje również -d ''. Naprawię moją odpowiedź. Dzięki, że dałeś mi znać.
Wstrzymano do odwołania.
Ups, ten, -rktóry chroni `\` wypadł. Chciałbym, aby właściwe przetwarzanie danych binarnych w programach powłoki nie było tak skomplikowane. Seems Wydaje się niemożliwe dokładne odwzorowanie 00 na środku łańcucha. Twoja metoda jednoznakowa na raz obsługuje 00 dzięki wygodnej (zaprojektowanej?) Współpracy między readinterpolacją ciągów znaków i printftraktowaniu argumentu jednoznakowego '. Westchnienie.
Chris Johnsen,
@Chris: Chciałbym, żeby mój procesor DWIM nie był zawalony. Nawiasem mówiąc, być może zainteresuje Cię napisany przeze mnie skrypt Bash , który powiela podstawową funkcjonalność hexdump -C.
Wstrzymano do odwołania.
Dodatkowe +1, jeśli możesz wyjaśnić, co się dzieje i dlaczego Twoje rozwiązanie działa.
Jed Daniels,
7

Najkrótszym sposobem, jaki mogłem wymyślić, było użycie zrzutu heksadecymalnego bezpośrednio

echo 00-60-2f$(hexdump -n3 -e '/1 "-%02X"' /dev/random)
  • -n3 mówi heksdumpowi, aby odczytał trzy bajty
  • Ciąg formatu drukuje myślnik i dwucyfrową wartość szesnastkową dla każdego bajtu
    • „/ 1” oznacza zastosowanie formatu dla każdego odczytanego bajtu
    • „-% 02X” to specyfikacja printf do drukowania wiodącej zerowej, dwucyfrowej, dużej wartości szesnastkowej
  • / dev / random to losowe bajty źródłowe

Testowany na GNU / Linux

maxthoursie
źródło
Skuteczność uniksowa w pracy :-)
artistoex,
hexdump -n3 -e'/3 "00-60-2F" 3/1 "-%02X"' /dev/randomjest nieco krótszy :-)
artistoex
4

Kolejne rozwiązanie jednoliniowe

$ echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g'

To samo wielkie litery

$ echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g' | tr '[:lower:]' '[:upper:]'

Wygeneruj go dla zmiennej środowiskowej Bash

$ export MAC=$(echo '00 60 2f'$(od -An -N3 -t xC /dev/urandom) | sed -e 's/ /-/g')
$ echo $MAC

Detale:

  • od (ósemkowy zrzut)

    -AnPomija wiodącą reprezentację adresu (dodatkowy szum) na wyjściu.
    -N3Ogranicz dane wyjściowe do trzech bajtów.
    -t xCDane wyjściowe w postaci szesnastkowej, ASCII, zgodnie z życzeniem.
    /dev/urandomPseudo-plik jądra systemu Linux.

  • sed (edytor strumieniowy) Dla podstawienia spacją do łącznika.

    -e <SCRIPT> wykonać skrypt sed.

  • tr (tłumaczenie napisów) Opcjonalne, w tym przykładzie. W moich skryptach / środowisku lubię duże adresy MAC.

zero2cx
źródło
2
#!/bin/bash
#Creates an array containing all hexadecimal characters
HEX=(a b c d e f 0 1 2 3 4 5 6 7 8 9)
#Defines MAC string length as 0 (total SL will be 17)
SL=0
#Loop sequentially assigns random hex characters in pairs until a full
#MAC address is generated.
while [ $SL -lt 17 ]
do
        num=`shuf -i 0-15 -n 1` #Generates random number which will be used as array index
        RMAC="$RMAC""${HEX[$num]}" #Uses the randomly generated number to select a hex character
        num=`shuf -i 0-15 -n 1` #New random number
        RMAC="$RMAC""${HEX[$num]}" #Appends second hex character
        SL=$[`echo $RMAC | wc -c` - 1] #Calculates SL and stores in var SL
    if [ $SL -lt 17 ] #If string is uncomplete, appends : character
            then
            RMAC=""$RMAC":"
    fi
done
echo $RMAC #Displays randomly generated MAC address
Krwiak
źródło
2

To powinno działać

echo 00-60-2f-`openssl rand -hex 3 | sed 's/\(..\)/\1-/g; s/.$//'`
linuxrules94
źródło
0
end=$( echo $RANDOM | openssl md5 | sed 's/\(..\)/\1-/g' | cut -b-8 )
echo 00-60-2f-$end
Kevin Duterne
źródło
5
Dodatkowe +1, jeśli możesz wyjaśnić, co się dzieje i dlaczego Twoje rozwiązanie działa.
Jed Daniels,
0

Ten też działa. W razie potrzeby dane wyjściowe są pisane wielkimi literami.

openssl rand -hex 3 | sed 's/\(..\)\(..\)\(..\)/00-60-2F-\1-\2-\3/' | tr [a-f] [A-F]
Jaroslav Kucera
źródło
0

Działa to w klasycznym #!/bin/shskrypcie shell ( ):

random_mac() {
    printf '%.2x\n' "$(shuf -i 0-281474976710655 -n 1)" | sed -r 's/(..)/\1:/g' | cut -d: -f -6
}

Lub jeśli chcesz mieć niestandardowy prefiks:

random_mac_with_prefix() {
    echo -n "00:60:2f:" &&
    printf '%.2x\n' "$(shuf -i 0-281474976710655 -n 1)" | sed -r 's/(..)/\1:/g' | cut -d: -f -3
}

Przykładowe użycie:

$ random_mac
96:ef:45:28:45:25
$ random_mac
7e:47:26:ae:ab:d4
$ random_mac_with_prefix 
00:60:2f:24:f4:18
$ random_mac_with_prefix 
00:60:2f:63:08:b2
kvaps
źródło
0

Inną opcją jest użycie jot:

echo 00-60-2F-$(jot -w%02X -s- -r 3 0 256)

-wzmienia format, -szmienia separator i -rgeneruje liczby losowe.

Polecenia użyte odw odpowiedziach opublikowanych przez artistoex i zero2cx dodają dodatkowe myślniki do danych wyjściowych w OS X od, ale to nie:

echo 00-60-2f-$(od -tx1 -An -N3 /dev/random|awk '$1=$1'|tr \  -)

OS X od( /usr/bin/odponiżej) używa innego formatu wyjściowego niż GNU od:

$ /usr/bin/od -N3 -tx1 -An /dev/random|tr ' ' -
-----------c7--fd--55----------------------------------------------------

$ god -N3 -tx1 -An /dev/random|tr ' ' -
-94-9e-5c
nisetama
źródło
1
Uwaga na jota. Mam wygenerowane w ten sposób mac, które ma w sobie „100”, np. 00-60-2F-100-A3-F6 ...
petrus
@petrus Masz rację, zredagowałem odpowiedź, aby zmienić jot -w%02X -s- -r 3 1 256na jot -w%02X -s- -r 3 0 256.
nisetama,
0

W systemie Linux:

printf '00-60-2f-' && cut -b 7-11,24-26 /proc/sys/kernel/random/uuid

Wyjaśnienie:

W systemie Linux /proc/sys/kernel/random/uuidzwraca nowy UUID typu 4 (losowy) za każdym razem, gdy go czytasz. Większość jego znaków to (pseudo) losowe cyfry szesnastkowe, więc możemy ich użyć. Na przykład:

$ cat /proc/sys/kernel/random/uuid
5501ab12-b530-4db5-a8ea-3df93043f172
$ #           ^    ^       Beware, these characters are not random.
$ #   ^^^^^            ^^^ Let's use characters on these positions.
$ cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
6d-74-a1
$ cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
13-f9-75

Teraz wystarczy 00-60-2f-najpierw wydrukować (bez nowej linii):

$ printf '00-60-2f-' && cut -b 7-11,24-26 /proc/sys/kernel/random/uuid
00-60-2f-86-f9-21

Plusy:

  • cyfry szesnastkowe od samego początku, nie jest wymagana konwersja / filtrowanie;
  • printfi cutsą narzędziami POSIX;
  • (w twoim konkretnym przypadku) łączniki już w UUID, używamy ich.

Cons:

  • musimy pamiętać o dwóch nieprzypadkowych cyfrach w UUID;
  • /proc/sys/kernel/random/uuid może nie być dostępny w niektórych systemach;
  • tak proste są tylko małe litery (potrzebujesz dodatkowego kroku, aby uzyskać wielkie litery).
Kamil Maciorowski
źródło
0

Jedna wkładka (bash)

mac=$(c=0;until [ $c -eq "6" ];do printf ":%02X" $(( $RANDOM % 256 ));let c=c+1;done|sed s/://)

wynik

$ echo $mac
93:72:71:0B:9E:89
Zibri
źródło