CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/proto/ntp/header.rb
Views: 15959
1
# -*- coding: binary -*-
2
3
require 'bindata'
4
require 'bigdecimal'
5
require 'bigdecimal/util'
6
7
module Rex
8
module Proto
9
module NTP::Header
10
11
class NTPShort < BinData::Primitive
12
# see: https://datatracker.ietf.org/doc/html/rfc5905#section-6
13
endian :big
14
15
uint16 :seconds
16
uint16 :fraction
17
18
def set(value)
19
value = value.to_d
20
seconds = value.floor
21
self.seconds = seconds
22
self.fraction = ((value - seconds) * BigDecimal(2**16)).round
23
end
24
25
def get
26
BigDecimal(seconds.value) + (BigDecimal(fraction.value) / BigDecimal(2**16))
27
end
28
end
29
30
class NTPTimestamp < BinData::Primitive
31
UNIX_EPOCH = Time.utc(1900, 1, 1)
32
# see: https://datatracker.ietf.org/doc/html/rfc5905#section-6
33
endian :big
34
35
uint32 :seconds
36
uint32 :fraction
37
38
def get
39
return nil if seconds == 0 && fraction == 0
40
41
time_in_seconds = seconds + BigDecimal(fraction.to_s) / BigDecimal((2**32).to_s)
42
(UNIX_EPOCH + time_in_seconds).utc
43
end
44
45
def set(time)
46
if time.nil?
47
seconds = fraction = 0
48
else
49
seconds_since_epoch = time.to_r - UNIX_EPOCH.to_r
50
seconds = seconds_since_epoch.to_i
51
fraction = ((seconds_since_epoch - seconds) * (2**32)).to_i
52
end
53
54
self.seconds = seconds
55
self.fraction = fraction
56
end
57
end
58
59
class NTPExtension < BinData::Record
60
endian :big
61
62
uint16 :ext_type
63
uint16 :ext_length
64
uint8_array :ext_value, initial_length: :ext_length
65
end
66
67
# A unified structure capable of representing NTP versions 1-4
68
class NTPHeader < BinData::Record
69
# see: https://datatracker.ietf.org/doc/html/rfc958 (NTP v0 - unsupported)
70
# see: https://datatracker.ietf.org/doc/html/rfc1059 (NTP v1)
71
# see: https://datatracker.ietf.org/doc/html/rfc1119 (NTP v2)
72
# see: https://datatracker.ietf.org/doc/html/rfc1305 (NTP v3)
73
# see: https://datatracker.ietf.org/doc/html/rfc5905 (NTP v4)
74
endian :big
75
hide :bytes_remaining_0, :bytes_remaining_1
76
77
bit2 :leap_indicator
78
bit3 :version_number, initial_value: 4, assert: -> { version_number.between?(1, 4) }
79
bit3 :mode, onlyif: -> { version_number > 1 }
80
resume_byte_alignment
81
uint8 :stratum
82
int8 :poll
83
int8 :precision
84
ntp_short :root_delay
85
ntp_short :root_dispersion
86
string :reference_id, length: 4, trim_padding: true
87
ntp_timestamp :reference_timestamp
88
ntp_timestamp :origin_timestamp
89
ntp_timestamp :receive_timestamp
90
ntp_timestamp :transmit_timestamp
91
count_bytes_remaining :bytes_remaining_0
92
buffer :extensions, length: -> { bytes_remaining_0 - 20 }, onlyif: :has_extensions? do
93
array :extensions, type: :ntp_extension, read_until: :eof
94
end
95
count_bytes_remaining :bytes_remaining_1
96
uint32 :key_identifier, onlyif: :has_key_identifier?
97
uint8_array :message_digest, initial_length: OpenSSL::Digest::MD5.new.digest_length, onlyif: :has_message_digest?
98
99
private
100
101
def has_extensions?
102
# -20 for the length of the key identifier and message digest which are required when extensions are present
103
bytes_remaining_0 - 20 > 0 && version_number > 3
104
end
105
106
def has_key_identifier?
107
bytes_remaining_1 > 0 || !key_identifier.clear?
108
end
109
110
def has_message_digest?
111
bytes_remaining_1 > 4 || !message_digest.clear?
112
end
113
end
114
115
end
116
end
117
end
118
119