diff --git a/README.md b/README.md index e69de29..b7bc42b 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,75 @@ + Network Working Group T. Wensing - Individual Contributor + +Request for Comments: XXX C. Merten - Individual Contributor + + Aug 2019 + + IPv6 Multicast Time Protocol + +This RFC specifies a standard for the ARPA Internet community. Hosts on + +IPv6 that choose to implement a Time Protocol are expected + +to adopt and implement this standard. + +This protocol provides a site-independent, machine readable date and + +time. The time service sends back to the originating source the time in + +seconds since midnight on January first 1900. + +One motivation arises from the fact that not all systems have a + +date/time clock, and all are subject to occasional human or machine + +error. The use of time-servers makes it possible to quickly confirm or + +correct a system's idea of the time, by making a brief poll of several + +independent sites on the network. + +This protocol may be used either with Link-Local Scope Multicast Addresses or Site-Local Scope Multicast Addresses. + +When used via Link-Local Scope Multicast Addresses the time service works as follows: + +S: Listen on Multicast Address FF02:0:0:0:0:0:0:37 + +U: Send empty packet to Multicast Address + +S: Send the time as a 32 bit binary coded IPv6 Address. + +U: Receive the packet. + +U: Close the connection. + +S: Close the connection. + +The server listens for a connection on Internet Protocol Version 6 Multicast Address FF02:0:0:0:0:0:0:10. + +If the server is unable to determine the time at its + +site, it should either refuse the connection or close it without + +sending anything. + +The Time + +The time is the number of seconds since 00:00 (midnight) 1 January 1900 + +GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this + +base will serve until the year 2036. + +For example: + +the time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT, + + 2,398,291,200 corresponds to 00:00 1 Jan 1976 GMT, + + 2,524,521,600 corresponds to 00:00 1 Jan 1980 GMT, + + 2,629,584,000 corresponds to 00:00 1 May 1983 GMT, + + and -1,297,728,000 corresponds to 00:00 17 Nov 1858 GMT + + diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..e0b4363 --- /dev/null +++ b/notes.txt @@ -0,0 +1,9 @@ +https://en.wikipedia.org/wiki/Time_Protocol +RFC 868 rdate computer readable +RFC 867 human readable + +https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml +https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml + +user readable +sudo socat tcp-listen:13,fork,reuseaddr exec:date diff --git a/python/multicast-timeservice/timeservice.py b/python/multicast-timeservice/timeservice.py new file mode 100755 index 0000000..70ed253 --- /dev/null +++ b/python/multicast-timeservice/timeservice.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +from socket import AF_INET6, AF_INET +import socket +from socket import AddressFamily +import struct + +# Bugfix for Python 3.6 for Windows ... missing IPPROTO_IPV6 constant +#if not hasattr(socket, 'IPPROTO_IPV6'): +# socket.IPPROTO_IPV6 = 41 + +multicast_address = { + AF_INET: ["224.0.1.37"], + AF_INET6: ["FF02:0:0:0:0:0:0:37"] +} +multicast_port = 37 + +def get_ips(): + ipv4 = list() + ipv6 = list() + for item in socket.getaddrinfo(socket.gethostname(), None): + protocol, *_, (ip, *_) = item + if protocol == AddressFamily.AF_INET: + ipv4.append(ip) + elif protocol == AddressFamily.AF_INET6: + ipv6.append(ip) + + return ipv4, ipv6 + + +if __name__ == '__main__': + all_ipv4, all_ipv6 = get_ips() + print(all_ipv4) + print(all_ipv6) + + +addr_info = socket.getaddrinfo('127.0.0.1', None) # get all ip +for addr in addr_info: + family = addr[0] + local_address = addr[4][0] + print(local_address) + + sock = socket.socket(family, socket.SOCK_DGRAM, socket.IPPROTO_UDP) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.bind((local_address, multicast_port)) + if family == AF_INET: + for multicast_group in multicast_address[family]: + sock.setsockopt( + socket.IPPROTO_IP, + socket.IP_ADD_MEMBERSHIP, + socket.inet_aton(multicast_group) + socket.inet_aton(local_address) + ) + elif family == AF_INET6: + for multicast_group in multicast_address[family]: + ipv6mr_interface = struct.pack('i', addr[4][3]) + ipv6_mreq = socket.inet_pton(socket.AF_INET6, multicast_group) + ipv6mr_interface + sock.setsockopt( + socket.IPPROTO_IPV6, + socket.IPV6_JOIN_GROUP, + ipv6_mreq + ) +# _transport, _protocol = await loop.create_datagram_endpoint( +# lambda: protocol_factory(), sock=sock) + + diff --git a/python/multicast-timeservice/timetick.py b/python/multicast-timeservice/timetick.py new file mode 100755 index 0000000..fe0d990 --- /dev/null +++ b/python/multicast-timeservice/timetick.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import sched, time + +s = sched.scheduler(time.monotonic, time.sleep) +def print_time(a='default'): + print("From print_time", time.time(), a) + + +s.enter(1, 1, print_time, kwargs={'a': 'keyword'}) +s.run() diff --git a/rust/multicast-timeservice/.gitignore b/rust/multicast-timeservice/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/rust/multicast-timeservice/.gitignore @@ -0,0 +1 @@ +target diff --git a/rust/multicast-timeservice/Cargo.lock b/rust/multicast-timeservice/Cargo.lock new file mode 100644 index 0000000..e72ce9d --- /dev/null +++ b/rust/multicast-timeservice/Cargo.lock @@ -0,0 +1,42 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "multicast-timeservice" +version = "0.1.0" +dependencies = [ + "time", +] + +[[package]] +name = "serde" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" + +[[package]] +name = "time" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +dependencies = [ + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] diff --git a/rust/multicast-timeservice/Cargo.toml b/rust/multicast-timeservice/Cargo.toml new file mode 100644 index 0000000..34096b7 --- /dev/null +++ b/rust/multicast-timeservice/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "multicast-timeservice" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +time = { version = "0.3", features = ["macros"] } diff --git a/rust/multicast-timeservice/src/main.rs b/rust/multicast-timeservice/src/main.rs new file mode 100644 index 0000000..9428b4d --- /dev/null +++ b/rust/multicast-timeservice/src/main.rs @@ -0,0 +1,31 @@ +use std::env; +use std::time::SystemTime; +use time::OffsetDateTime; + +use std::net::{Ipv6Addr, SocketAddrV6}; +use std::net::UdpSocket; + +fn print_time() { + let now = OffsetDateTime::now_utc(); + // let local = OffsetDateTime::now_local(); + + println!("{now}"); + //println!("{local}"); +} + +fn ipv6_multicastListener() { + let socket = SocketAddrV6::new(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1), 8080, 0, 0); + + assert_eq!("[2001:db8::1]:8080".parse(), Ok(socket)); + assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); + assert_eq!(socket.port(), 8080); + +} + +fn main() { + let args: Vec = env::args().collect(); + println!("multicast timeservice like the old RFC 868"); + print_time(); + + ipv6_multicastListener(); +}