1## This file is part of Scapy
2## See http://www.secdev.org/projects/scapy for more informations
3## Copyright (C) Philippe Biondi <phil@secdev.org>
4## This program is published under a GPLv2 license
5
6"""
7NTP (Network Time Protocol).
8"""
9
10import time
11from scapy.packet import *
12from scapy.fields import *
13from scapy.layers.inet import UDP
14
15
16# seconds between 01-01-1900 and 01-01-1970
17_NTP_BASETIME = 2208988800
18
19class TimeStampField(FixedPointField):
20    def __init__(self, name, default):
21        FixedPointField.__init__(self, name, default, 64, 32)
22
23    def i2repr(self, pkt, val):
24        if val is None:
25            return "--"
26        val = self.i2h(pkt,val)
27        if val < _NTP_BASETIME:
28            return val
29        return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(val-_NTP_BASETIME))
30
31    def any2i(self, pkt, val):
32        if type(val) is str:
33            return int(time.mktime(time.strptime(val))) + _NTP_BASETIME + 3600 # XXX
34        return FixedPointField.any2i(self,pkt,val)
35
36    def i2m(self, pkt, val):
37        if val is None:
38            val = FixedPointField.any2i(self, pkt, time.time()+_NTP_BASETIME)
39        return FixedPointField.i2m(self, pkt, val)
40
41
42
43class NTP(Packet):
44    # RFC 1769
45    name = "NTP"
46    fields_desc = [
47         BitEnumField('leap', 0, 2,
48                      { 0: 'nowarning',
49                        1: 'longminute',
50                        2: 'shortminute',
51                        3: 'notsync'}),
52         BitField('version', 3, 3),
53         BitEnumField('mode', 3, 3,
54                      { 0: 'reserved',
55                        1: 'sym_active',
56                        2: 'sym_passive',
57                        3: 'client',
58                        4: 'server',
59                        5: 'broadcast',
60                        6: 'control',
61                        7: 'private'}),
62         BitField('stratum', 2, 8),
63         BitField('poll', 0xa, 8),          ### XXX : it's a signed int
64         BitField('precision', 0, 8),       ### XXX : it's a signed int
65         FixedPointField('delay', 0, size=32, frac_bits=16),
66         FixedPointField('dispersion', 0, size=32, frac_bits=16),
67         IPField('id', "127.0.0.1"),
68         TimeStampField('ref', 0),
69         TimeStampField('orig', None),  # None means current time
70         TimeStampField('recv', 0),
71         TimeStampField('sent', None)
72         ]
73    def mysummary(self):
74        return self.sprintf("NTP v%ir,NTP.version%, %NTP.mode%")
75
76
77bind_layers( UDP,           NTP,           dport=123, sport=123)
78