I played a bit with the idea this morning, and I think this is how I would
do it:
+-------+-----------+-----+---------------------+---------------+
|1 1 1 1|M M M M M M M M M|L L L L L L L L L|D D|C C C C C C C C|
+-------+-----------+-----+---------------------+---------------+
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
The first four bits are constant 0xf putting the resulting IPv4 in
the "Class-E" segment which is reserved. This should give us 100%
certainty in detecting meddling DNS resolvers.
The "M" field is nine bit unsigned month number:
(year - 1972) * 12 + month - 1
The "L" field the eight bit signed(!) TAI-UTC difference before the
start of the indicated month.
The "D" field is two bit signed TAI-UTC change before the start of
the indicated month.
The "C" field is a CRC8 with poly=0xcf (found by exhaustive search)
Here are how recent Bulletin-C's would look:
YYYY MM before after encoded crc IP Decoded
-------------------------------------------------------------------------
2012 1 34 34 f7808800 65 247.128.136.101 -> OK 2012 1 +34 +0
2012 7 34 35 f7988900 66 247.152.137.102 -> OK 2012 7 +34 +1
2013 1 35 35 f7b08c00 0b 247.176.140.11 -> OK 2013 1 +35 +0
2013 7 35 35 f7c88c00 58 247.200.140.88 -> OK 2013 7 +35 +0
2014 1 35 35 f7e08c00 69 247.224.140.105 -> OK 2014 1 +35 +0
2014 7 35 35 f7f88c00 f3 247.248.140.243 -> OK 2014 7 +35 +0
2015 1 35 35 f8108c00 be 248.16.140.190 -> OK 2015 1 +35 +0
2015 7 35 36 f8288d00 fa 248.40.141.250 -> OK 2015 7 +35 +1
-------------------------------------------------------------------------
Attached is a proof of concept in python.
You can poke the result at my test-domain "leap.net-tid.dk"
Poul-Henning
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
[email protected] | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.
#!/usr/local/bin/python
from __future__ import print_function
import httplib
conn = None
def fetch_url(url):
global conn
print("Fetch", url)
if conn == None:
conn = httplib.HTTPConnection("hpiers.obspm.fr")
conn.request("GET", url)
r1 = conn.getresponse()
if r1.status != 200:
print (r1.status, r1.reason)
exit(2)
data1 = r1.read()
time.sleep(random.uniform(1,2))
return data1
def cache_url(fn, url):
try:
fi = open("_Cache_%s" % fn)
x = fi.read()
fi.close()
return x
except:
x = fetch_url(url)
fi = open("_Cache_%s" % fn, "w")
fi.write(x)
fi.close()
return x
raw_data = cache_url(
"Leap_Second_History.dat",
"http://hpiers.obspm.fr/iers/bul/bulc/Leap_Second_History.dat"
)
def crc8(b):
poly = 0xcf
# I chose 0xcf after an exhaustive search for best performance
# on 28 bit messages.
#
# bit- Missed Total Miss-Rate
# errors
# -------------------------------------
# <=1 0 28 0.000000
# <=2 0 406 0.000000
# <=3 0 3682 0.000000
# <=4 81 24157 0.003353
# <=5 532 122437 0.004345
# <=6 1972 499177 0.003951
# <=7 6494 1683217 0.003858
# <=8 18736 4791322 0.003910
# -------------------------------------
crc = 0
for i in b:
for j in range(8):
mix = (crc ^ i) & 0x01
crc >>= 1
if mix:
crc ^= poly
i >>= 1
return crc
def dec(i):
r = ""
j = i.split(".")
assert len(j) == 4
for k in range(4):
j[k] = int(j[k])
if crc8(j) == 0:
r += "OK "
else:
r += "BAD"
w = j[0] << 16
w |= j[1] << 8
w |= j[2]
assert w & 0xf00000 == 0xf00000
w &= ~0xf00000
d = w & 0x03
w >>= 2
b = w & 0xff
w >>= 8
mn = w
m = (mn % 12) + 1
y = mn / 12 + 1972
assert d != 2
if d == 3:
d = -1
r += " %04d" % y
r += " %2d" % m
r += " %+4d" % b
r += " %+2d" % d
return r
def enc(y, m, b, a):
mn = (y - 1972) * 12 + (m-1)
w = mn
w <<= 8
w |= b
w <<= 2
if a == b + 1:
w |= 0x1
elif a == b - 1:
w |= 0x3
w <<= 8
w |= 0xf0000000
z = [w >> 24, (w >> 16) & 0xff, (w >> 8) & 0xff]
z.append(crc8(z))
assert crc8(z) == 0
i = "%d.%d.%d.%d" % (z[0], z[1], z[2], z[3])
print("%4d %2d %6d %6d %08x %02x %15s -> %s" %
(y, m, b, a, w, z[3], i, dec(i)))
print("YYYY MM before after encoded crc IP Decoded")
print("-" * 73)
ll = list()
lmnum = 6
ldut1 = 9
for l in raw_data.split("\n"):
i = l.split()
if len(i) == 0 or i[0][0] == "#":
continue
assert i[1] == "1"
month = int(i[2])
assert month >= 1 and month <= 12
year = int(i[3])
assert year >= 1972
dut1 = int(i[4])
mnum = (year - 1972) * 12 + month - 1
for x in range(lmnum, mnum, 6):
y = 1972 + (x+1) // 12
m = (x+1) % 12
enc(y, m, ldut1, ldut1)
enc(year, month, ldut1, dut1)
lmnum = mnum + 6
ldut1 = dut1
print("")
for year in range(2015, 2143):
enc(year, month, ldut1, dut1)
print("-" * 73)
_______________________________________________
LEAPSECS mailing list
[email protected]
https://pairlist6.pair.net/mailman/listinfo/leapsecs