Skip to content

Commit ac397b4

Browse files
committed
use xor for generate_mac
- add entropy / reduce probability of mac collisions - makes macs more opaque / non-sequential - SQUASH THIS
1 parent 4368df1 commit ac397b4

File tree

2 files changed

+20
-21
lines changed

2 files changed

+20
-21
lines changed

lib/puppet/functions/generate_mac.rb

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# frozen_string_literal: true
22

3-
require 'digest'
3+
require "digest"
44

55
# generates a deterministic pseudorandom mac address, using hostname as seed
66
#
@@ -12,27 +12,27 @@
1212
#
1313
# generated address contains
1414
# - 3 byte fixed OUI (prefix)
15-
# - 21 "random" bits (seeded from hostname)
16-
# - 3 bit sequential number (index)
15+
# - 3 "random" byte (seeded from hostname)
16+
# - XOR with up to 3 bits (index) for additonal interfaces
1717
Puppet::Functions.create_function(:generate_mac) do
1818
dispatch :generate_mac do
1919
param "String", :prefix
2020
param "String", :hostname
21-
param "Integer", :index
21+
optional_param "Integer", :index
2222
end
2323

24-
def generate_mac(prefix, hostname, index)
25-
unless(index.between?(0,7))
24+
def generate_mac(prefix, hostname, index = 0)
25+
unless index.between?(0, 7)
2626
raise(ArgumentError, "#{index} must be between 0 and 7, I can only generate 8 mac addresses per host!")
2727
end
2828

29-
oui = prefix.downcase.gsub(/[^0-9a-z]/,'')
30-
unless(oui =~ /^[a-f0-9][26ae][a-f0-9]{4}$/)
29+
oui = prefix.downcase.gsub(/[^0-9a-z]/, "")
30+
unless /^[a-f0-9][26ae][a-f0-9]{4}$/.match?(oui)
3131
raise(ArgumentError, "invalid mac prefix!")
3232
end
3333

34-
integer_id = (Digest::SHA256.hexdigest(hostname)[0,6].to_i(16) & 0xFF_FF_F8) + index
35-
hex_id = sprintf('%06x',integer_id)
36-
"#{oui}#{hex_id}".each_char.each_slice(2).map{|x| x.join}.join(':')
34+
integer_id = Digest::SHA256.hexdigest(hostname)[0, 6].to_i(16) ^ index
35+
hex_id = sprintf("%06x", integer_id)
36+
"#{oui}#{hex_id}".each_char.each_slice(2).map { |x| x.join }.join(":")
3737
end
3838
end

spec/functions/generate_mac_spec.rb

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,22 @@
77

88
describe "generate_mac" do
99
it "generates simple addresses" do
10-
is_expected.to run.with_params('02:00:00', 'example.com', 0).and_return('02:00:00:a3:79:a0')
11-
is_expected.to run.with_params('12-0f-00', 'example.com', 2).and_return('12:0f:00:a3:79:a2')
10+
is_expected.to run.with_params("02:00:00", "example.com").and_return("02:00:00:a3:79:a6")
11+
is_expected.to run.with_params("12-0f-00", "example.com", 2).and_return("12:0f:00:a3:79:a4")
1212
end
1313
it "fails on invalid chars" do
14-
is_expected.to run.with_params('g2:00:00', 'example.com', 0).and_raise_error(ArgumentError)
14+
is_expected.to run.with_params("g2:00:00", "example.com", 0).and_raise_error(ArgumentError)
1515
end
1616
it "correctly masks final 3 bits" do
17-
is_expected.to run.with_params('06 12 34', 'my.host.name', 0).and_return('06:12:34:3b:d9:98')
18-
is_expected.to run.with_params('5a.67.89', 'my.host.name', 3).and_return('5a:67:89:3b:d9:9b')
19-
is_expected.to run.with_params('AE:BC:DE', 'my.host.name', 7).and_return('ae:bc:de:3b:d9:9f')
17+
is_expected.to run.with_params("06 12 34", "my.host.name", 0).and_return("06:12:34:3b:d9:9a")
18+
is_expected.to run.with_params("5a.67.89", "my.host.name", 3).and_return("5a:67:89:3b:d9:99")
19+
is_expected.to run.with_params("AE:BC:DE", "my.host.name", 7).and_return("ae:bc:de:3b:d9:9d")
2020
end
2121
it "fails on non-private oui" do
22-
is_expected.to run.with_params('03:00:00', 'example.com', 0).and_raise_error(ArgumentError)
22+
is_expected.to run.with_params("03:00:00", "example.com", 0).and_raise_error(ArgumentError)
2323
end
2424
it "fails on out of range index" do
25-
is_expected.to run.with_params('02:00:00', 'example.com', 11).and_raise_error(ArgumentError)
26-
is_expected.to run.with_params('02:00:00', 'example.com', -1).and_raise_error(ArgumentError)
25+
is_expected.to run.with_params("02:00:00", "example.com", 11).and_raise_error(ArgumentError)
26+
is_expected.to run.with_params("02:00:00", "example.com", -1).and_raise_error(ArgumentError)
2727
end
2828
end
29-

0 commit comments

Comments
 (0)