TimeProtocol: time-rfc868-ext.py

File time-rfc868-ext.py, 2.4 kB (added by Dirk Loss, 9 months ago)
Line 
1 """
2 Time protocol (RFC 868) extension for Scapy <http://www.secdev.org/scapy>
3
4 Copyright (c) 2008 Dirk Loss  :  mail dirk-loss de
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 """
16
17 from scapy import *
18
19 EXT_VERSION = "v0.2"
20
21 # Seconds between Unix epoch (1970-01-01) and NTP epoch (1900-01-01)
22 EPOCH1900_DIFF = 2208988800
23
24 class IntTimeField(IntField):
25     """ Human readable timestamp (seconds since midnight 1900-01-01, as in RFC 868) """
26     def i2h(self, pkt, x):
27         return time.ctime(x - EPOCH1900_DIFF)
28
29 class TIME_Req(Packet):
30     name = "TIME protocol (RFC 868) request"
31     # TIME requests do not have to have a payload, but correctly dissecting
32     # UDP datagrams without payload is hard
33     fields_desc = [ StrField("request", "\n") ]
34    
35 class TIME_Resp(Packet):
36     name = "TIME protocol (RFC 868) response"   
37     fields_desc = [ IntTimeField("time_stamp", IntAutoTime(base=-EPOCH1900_DIFF))]
38    
39     def answers(self, other):
40         return isinstance(other, TIME_Req)
41
42
43 class TIME_am(AnsweringMachine):
44     function_name="TIME_server"
45     filter = "udp port 37"
46
47     def is_request(self, req):
48         # We cannot use 'isinstance(req, TIME_Req)' here because the request
49         # may not have a payload and thus would not be decoded as TIME_Req
50         return (req.haslayer(UDP) and req[UDP].dport == 37)
51    
52     def make_reply(self, req):
53         timestamp = struct.pack("!I", int(time.time() + EPOCH1900_DIFF))
54         ip = req.getlayer(IP)
55         return IP(dst=ip.src, src=ip.dst)/UDP(dport=ip.sport,sport=ip.dport)/Raw(timestamp)
56
57
58 # Overloading the source port makes sure that we do not interfere with UDP's default (DNS)   
59 bind_layers(UDP, TIME_Req, dport=37, sport=3737)
60 bind_layers(UDP, TIME_Resp, sport=37)
61
62 # Some RFC 868 time servers: time-a.nist.gov, time-nw.nist.gov, nist.expertsmi.com
63 # A list is available at <http://tf.nist.gov/tf-cgi/servers.cgi> 
64
65 if __name__ == "__main__":
66     interact(mydict=globals(), mybanner="TIME protocol (RFC 868) extension %s" % EXT_VERSION)