Qoritaanka macmiil fudud oo NTP ah

Hello, Habrausers. Maanta waxaan rabaa inaan ka hadlo sida loo qoro macmiilkaaga fudud ee NTP. Asal ahaan, wada hadalku wuxuu u jeesan doonaa qaab dhismeedka xirmada iyo habka loo habeeyo jawaabta server-ka NTP. Koodhka waxaa lagu qori doonaa Python, sababtoo ah waxay aniga iila muuqataa in aysan jirin luqad ka fiican waxyaalahan oo kale. Connoisseurs waxay ogaan doonaan isku ekaanshaha koodhka iyo koodka ntplib - aniga waxaa igu dhiiri galiyay.

Haddaba waa maxay dhab ahaan NTP? NTP waa hab-maamuuska is-dhexgalka ee server-yada waqtiga saxda ah. Hab-maamuuska waxaa loo adeegsadaa mashiinno badan oo casri ah. Tusaale ahaan, adeegga w32tm ee daaqadaha.

Waxaa jira 5 nooc oo borotokoolka NTP ah. Midka koowaad, nooca 0 (1985, RFC958)), ayaa hadda loo arkaa mid duugoobay. Hadda kuwa cusub ayaa la isticmaalaa, 1st (1988, RFC1059), 2nd (1989, RFC1119), 3rd (1992, RFC1305) iyo 4th (1996, RFC2030). Noocyada 1-4 waxay ku habboon yihiin midba midka kale; waxay ku kala duwan yihiin kaliya algorithms hawlgalka server-ka.

Qaab xirmo

Qoritaanka macmiil fudud oo NTP ah

Tilmaamaha boodada (tusaale sax ah) - nambar tilmaamaya digniin ku saabsan isku-duwidda labaad. Macnaha:

  • 0 – sixid la'aan
  • 1-daqiiqada ugu danbeysa ee maalinta waxay ka kooban tahay 61 ilbiriqsi
  • 2 - daqiiqada ugu dambeysa ee maalinta waxay ka kooban tahay 59 ilbiriqsi
  • 3- Xubinta serverka (waqtiga lama wada shaqayn)

Lambarka Tilmaamaha (lambarka nooca) - lambarka nooca borotokoolka NTP (1-4).

mode (qaabka) - qaabka hawlgalka ee baqshadda soo diraha. Qiimaha laga bilaabo 0 ilaa 7, inta badan:

  • 3 - macmiilka
  • 4- server
  • 5 - habka baahinta

stratum (heerka lakabka) - tirada lakabyada dhexdhexaadka ah ee u dhexeeya server-ka iyo saacadda tixraaca (1 - server-ku wuxuu si toos ah xogta uga qaadaa saacadda tixraaca, 2 - server-ku wuxuu xogta ka qaataa server leh lakabka 1, iwm.).
pool waa tiro saxeexan oo ka dhigan inta u dhaxaysa farriimaha isku xiga. Macmiilka NTP ayaa halkan ku qeexaya inta u dhexaysa ee uu filayo inuu ku codeeyo serferka, iyo server-ka NTP wuxuu cadeeyaa inta u dhaxaysa uu filayo in la codeeyo. Qiimuhu wuxuu la mid yahay logarithm-ka binary ee ilbiriqsiyo.
sax (sax ahaan) waa isugeyn saxeexan oo ka dhigan saxnaanta saacadda nidaamka. Qiimuhu wuxuu la mid yahay logarithm-ka binary ee ilbiriqsiyo.
Daahitaanka xididka (Dib u dhac server) – wakhtiga ay qaadanayso in saacada la akhriyo si loo gaadho server-ka NTP, sida tiro go'an oo ilbiriqsi ah.
Kala firdhinta xididka (Faafidda serverka) - faafinta saacada server-ka NTP sida tiro ilbiriqsi ah oo leh bar go'an.
Tixraac id (Isha aqoonsiga) - saacada id. Haddii seerfarku leeyahay stratum 1, markaa ref id waa magaca saacada atomiga (4 ASCII characters). Haddii serfarka uu isticmaalo serfarka kale, markaas ref id waxa ku jira ciwaanka serfarkan.
4-ta goobood ee ugu dambeeya waxay matalaan waqtiga - 32 bits - qaybta isugeynta, 32 bits - qaybta jajabka.
Tixraaca - akhrinta saacada ugu dambeysay ee server-ka.
Asal ahaan - waqtiga xirmada la soo diray (buuxiyay server-ku - wax badan oo tan hoose ah).
Aqbala - waqtiga xirmada waxaa helay server-ka.
gudbiyaan - wakhtiga baakadda laga soo dirayo server-ka macmiilka (buuxiyay macmiilku, wax badan oo tan hoose ah).

Ma tixgelin doono labada goobood ee ugu dambeeya.

Aan qorno xirmadayada:

Koodhka xidhmada

class NTPPacket:
    _FORMAT = "!B B b b 11I"

    def __init__(self, version_number=2, mode=3, transmit=0):
        # Necessary of enter leap second (2 bits)
        self.leap_indicator = 0
        # Version of protocol (3 bits)
        self.version_number = version_number
        # Mode of sender (3 bits)
        self.mode = mode
        # The level of "layering" reading time (1 byte)
        self.stratum = 0
        # Interval between requests (1 byte)
        self.pool = 0
        # Precision (log2) (1 byte)
        self.precision = 0
        # Interval for the clock reach NTP server (4 bytes)
        self.root_delay = 0
        # Scatter the clock NTP-server (4 bytes)
        self.root_dispersion = 0
        # Indicator of clocks (4 bytes)
        self.ref_id = 0
        # Last update time on server (8 bytes)
        self.reference = 0
        # Time of sending packet from local machine (8 bytes)
        self.originate = 0
        # Time of receipt on server (8 bytes)
        self.receive = 0
        # Time of sending answer from server (8 bytes)
        self.transmit = transmit

Si aan u dirno (oo aan u helno) baakidh server-ka, waa in aan awoodno in aan u rogno qaab byte ah.
Hawlgalkan (iyo rogaal celiska), waxaanu qori doonaa laba hawlood - xirmo() iyo fur():

function xirmo

def pack(self):
        return struct.pack(NTPPacket._FORMAT,
                (self.leap_indicator << 6) + 
                    (self.version_number << 3) + self.mode,
                self.stratum,
                self.pool,
                self.precision,
                int(self.root_delay) + get_fraction(self.root_delay, 16),
                int(self.root_dispersion) + 
                    get_fraction(self.root_dispersion, 16),
                self.ref_id,
                int(self.reference),
                get_fraction(self.reference, 32),
                int(self.originate),
                get_fraction(self.originate, 32),
                int(self.receive),
                get_fraction(self.receive, 32),
                int(self.transmit),
                get_fraction(self.transmit, 32))

shaqada furto

def unpack(self, data: bytes):
        unpacked_data = struct.unpack(NTPPacket._FORMAT, data)

        self.leap_indicator = unpacked_data[0] >> 6  # 2 bits
        self.version_number = unpacked_data[0] >> 3 & 0b111  # 3 bits
        self.mode = unpacked_data[0] & 0b111  # 3 bits

        self.stratum = unpacked_data[1]  # 1 byte
        self.pool = unpacked_data[2]  # 1 byte
        self.precision = unpacked_data[3]  # 1 byte

        # 2 bytes | 2 bytes
        self.root_delay = (unpacked_data[4] >> 16) +
            (unpacked_data[4] & 0xFFFF) / 2 ** 16
         # 2 bytes | 2 bytes
        self.root_dispersion = (unpacked_data[5] >> 16) +
            (unpacked_data[5] & 0xFFFF) / 2 ** 16 

        # 4 bytes
        self.ref_id = str((unpacked_data[6] >> 24) & 0xFF) + " " + 
                      str((unpacked_data[6] >> 16) & 0xFF) + " " +  
                      str((unpacked_data[6] >> 8) & 0xFF) + " " +  
                      str(unpacked_data[6] & 0xFF)

        self.reference = unpacked_data[7] + unpacked_data[8] / 2 ** 32  # 8 bytes
        self.originate = unpacked_data[9] + unpacked_data[10] / 2 ** 32  # 8 bytes
        self.receive = unpacked_data[11] + unpacked_data[12] / 2 ** 32  # 8 bytes
        self.transmit = unpacked_data[13] + unpacked_data[14] / 2 ** 32  # 8 bytes

        return self

Dadka caajiska ah, sida codsi - koodka kaas oo baakadka u rogaya xadhig qurux badan

def to_display(self):
        return "Leap indicator: {0.leap_indicator}n" 
                "Version number: {0.version_number}n" 
                "Mode: {0.mode}n" 
                "Stratum: {0.stratum}n" 
                "Pool: {0.pool}n" 
                "Precision: {0.precision}n" 
                "Root delay: {0.root_delay}n" 
                "Root dispersion: {0.root_dispersion}n" 
                "Ref id: {0.ref_id}n" 
                "Reference: {0.reference}n" 
                "Originate: {0.originate}n" 
                "Receive: {0.receive}n" 
                "Transmit: {0.transmit}"
                .format(self)

U dirida xirmo server-ka

Baakad ay ku jiraan boosas buuxa waa in loo soo diraa server-ka Version, mode ΠΈ gudbiyaan. The gudbiyaan waa inaad ku qeexdaa wakhtiga hadda ee mishiinka maxaliga ah (tirada ilbiriqsi tan iyo January 1, 1900), version - mid ka mid ah 1-4, mode - 3 (qaabka macmiilka).

Server-ku, markii uu aqbalay codsiga, waxa uu buuxinayaa dhammaan goobaha ku jira xidhmada NTP, isaga oo ku koobiyaynaya goobta Asal ahaan qiimaha ka gudbiyaan, kaas oo ku yimid codsiga. Waa ii dahsoon sababta macmiilku aanu isla markiiba u buuxin karin qiimaha wakhtiga uu ku sugan yahay goobta Asal ahaan. Natiijo ahaan, marka baakidhku soo noqdo, macmiilku wuxuu leeyahay 4 qiime waqti - wakhtiga codsiga la soo diray (Asal ahaan), wakhtiga serverku uu helay codsiga (Aqbala), waqtiga serverku soo diray jawaabta (gudbiyaan) iyo wakhtiga macmiilku helay jawaabta - Soo qaado (kuma jiraan xirmada). Isticmaalka qiyamkan waxaan dejin karnaa waqtiga saxda ah.

Koodhka diritaanka iyo helitaanka xidhmada

# Time difference between 1970 and 1900, seconds
FORMAT_DIFF = (datetime.date(1970, 1, 1) - datetime.date(1900, 1, 1)).days * 24 * 3600
# Waiting time for recv (seconds)
WAITING_TIME = 5
server = "pool.ntp.org"
port = 123
    
packet = NTPPacket(version_number=2, mode=3, transmit=time.time() + FORMAT_DIFF)
answer = NTPPacket()
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    s.settimeout(WAITING_TIME)
    s.sendto(packet.pack(), (server, port))
    data = s.recv(48)
    arrive_time = time.time() + FORMAT_DIFF
    answer.unpack(data)

Ka baaraandegidda xogta server-ka

Habaynta xogta server-ka waxay la mid tahay falkii uu sameeyay mudane Ingriis ah oo ka soo jeeda dhibaatadii hore ee Raymond M. Smullyan (1978): β€œHal nin ma haysan saacada gacanta, laakiin waxaa jirtay saacad gidaar sax ah guriga, taas oo uu mararka qaar ilaaway. dabaysha. Maalin maalmaha ka mid ah, isagoo iloobay inuu mar kale dabaylo saacaddii, ayuu u aaday saaxiibkii, oo fiidkii la qaatay, markuu gurigii ku noqday, wuxuu ku guulaystay inuu saacadda si sax ah u dejiyo. Sidee buu u suurtageliyay inuu tan sameeyo haddii aan wakhtiga safarka la sii ogeyn? Jawaabtu waa: β€œMarka uu guriga ka baxayo, qofku wuxuu dabaylo saacaddiisa oo wuxuu xusuustaa meesha ay gacmihiisu yaalliin. Markuu u yimid saaxiibkii oo ka tagay martida, wuxuu xusayaa wakhtiga imaatinkiisa iyo bixitaankiisa. Tani waxay u ogolaaneysaa inuu ogaado inta uu socday booqashada. Ku soo noqoshada guriga oo fiirinaya saacadda, qofku wuxuu go'aamiyaa muddada maqnaanshihiisa. Marka laga jaro wakhtigan wakhtiga uu booqashada ku qaatay, qofku waxa uu ogaanayaa wakhtiga safarka uu ku qaatay halkaas iyo dib u soo noqoshada. Isagoo ku daraya kala badh wakhtiga lagu qaatay wadada wakhtiga martida laga tagayo, wuxuu helayaa fursad uu ku ogaado wakhtiga imaatinka guriga oo uu hagaajiyo gacmaha saacadiisa si waafaqsan. "

Soo hel wakhtiga seerfarka uu ku shaqaynayo codsiga:

  1. Ka hel wakhtiga safarka xidhmada ee macmiilka ilaa serverka: ((Imid – Asalka) – ( ​​Gudbi – Hesho)) / 2
  2. Soo hel farqiga u dhexeeya macmiilka iyo wakhtiga serverka:
    Qaado - Asal - ((Imid - Asal ahaan) - ( Gudbi - Hesho)) / 2 =
    2 * Qaado - 2 * Asal - Yimid + Asal + Gudbi - Hesho =
    Qaado - Asalka - Imaanshaha + Gudbinta

Waxaan ku darnaa qiimaha natiijada waqtiga maxalliga ah oo aan ku raaxaysanno nolosha.

Natiijada natiijada

time_different = answer.get_time_different(arrive_time)
result = "Time difference: {}nServer time: {}n{}".format(
    time_different,
    datetime.datetime.fromtimestamp(time.time() + time_different).strftime("%c"),
    answer.to_display())
print(result)

Faa'iido leh ссылка.

Source: www.habr.com

Add a comment