diff --git a/.github/workflows/generate-table.yml b/.github/workflows/generate-table.yml index c19dcec..17f0a3c 100644 --- a/.github/workflows/generate-table.yml +++ b/.github/workflows/generate-table.yml @@ -14,9 +14,13 @@ jobs: ref: ${{ github.ref }} - run: | + sudo apt-get update; + sudo apt-get upgrade -y; sudo apt-get install -y ntpsec-ntpdate; git config --global user.name "github-actions[bot]"; git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"; + pip3 install --upgrade pip; + pip3 install dnspython pyopenssl; python3 scripts/generate.py; git add -A; git commit -am "update table"; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..066c054 --- /dev/null +++ b/.gitignore @@ -0,0 +1,569 @@ +# Created by https://www.toptal.com/developers/gitignore/api/python,windows,linux,vs +# Edit at https://www.toptal.com/developers/gitignore?templates=python,windows,linux,vs + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### vs ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*[.json, .xml, .info] + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/python,windows,linux,vs \ No newline at end of file diff --git a/README-header.md b/README-header.md index 6458b50..874d01c 100644 --- a/README-header.md +++ b/README-header.md @@ -1,15 +1,18 @@ # aus-ntps -A collection of Australian NTP servers -The list below is generated by firstly `nslookup`ing the given endpoint to verify the host exists and then `ntpdig`ging it. Some endpoints may not have been accessible by the script which generates the list. For example, Aussie Broadband's NTP servers only respond to customers. The Australian Government's NTP servers are only available to [registered users](https://www.industry.gov.au/national-measurement-institute/physical-measurement-services/time-and-frequency-services). +A collection of Australian NTP servers Each table contains the following information: -- Endpoint: the hostname (or IP address) of the NTP server -- A/AAAA: `Y` indicates at least one A or AAAA DNS record exists for the given hostname -- IP Address: the IP address of the NTP server -- Stratum: the reported [stratum value](https://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_strata) of the NTP server -Use the Endpoint when configuring an NTP client or server. For example: +- **Endpoint**: the hostname (or IP address) and port number of the NTP server being queried +- **IP Address**: the IP address of the host +- **Version**: the NTP version of the NTP server +- **Stratum**: the reported [stratum value](https://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_strata) of the NTP server +- **Leap**: the reported leap indictor of the NTP server + +An endpoint may have zero or more IP address, version, stratum, and leap combinations. An endpoint with no entries indicates that a DNS record exists for the host, but that no NTP server exists or it was otherwise inaccessible by the Python script. For example, Aussie Broadband's NTP servers [only respond to customers](https://www.aussiebroadband.com.au/help-centre/internet/ntp-settings/). You may find it useful to test these endpoints yourself for this reason, particularly if the subdomain name of the endpoint begins with `ntp`, `time`, or one of the other [predefined names](src/NtpDnsProbeDiscoveryService.py#L14-L40). Further details about the information above can be obtained [here](https://docs.ntpsec.org/latest/ntpdig.html). + +You should use the endpoint when configuring an NTP client or server. For example: ```conf # /etc/ntpsec/ntp.conf @@ -18,7 +21,13 @@ server tic.ntp.telstra.net iburst ``` ## Useful Resources -- https://docs.ntpsec.org/latest/ntp_conf.html -- https://docs.ntpsec.org/latest/ntpdig.html -- https://docs.ntpsec.org/latest/ntpq.html -- bypass isp blocks on port 123 + +- If you are looking for the Australian Government's NTP servers, please be aware they are only available to [registered users](https://www.industry.gov.au/national-measurement-institute/physical-measurement-services/time-and-frequency-services). + +- Some ISPs may drop NTP traffic if the [outbound source port is port 123](https://docstore.mik.ua/orelly/networking_2ndEd/fire/ch22_05.htm) (well known NTP port number) and restrict access to some predefined ISP-controlled NTP servers. You may be able to bypass this restriction by altering the source port. One method is to add the [following iptables rule](https://superuser.com/a/1380558) to your router. + +```shell +iptables -t nat -I POSTROUTING -p udp -m udp --sport 123 -j MASQUERADE --to-ports 49152-65535 +``` + +## Servers diff --git a/README.md b/README.md index 7e93520..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,711 +0,0 @@ -# aus-ntps -A collection of Australian NTP servers - -The list below is generated by firstly `nslookup`ing the given endpoint to verify the host exists and then `ntpdig`ging it. Some endpoints may not have been accessible by the script which generates the list. For example, Aussie Broadband's NTP servers only respond to customers. The Australian Government's NTP servers are only available to [registered users](https://www.industry.gov.au/national-measurement-institute/physical-measurement-services/time-and-frequency-services). - -Each table contains the following information: -- Endpoint: the hostname (or IP address) of the NTP server -- A/AAAA: `Y` indicates at least one A or AAAA DNS record exists for the given hostname -- IP Address: the IP address of the NTP server -- Stratum: the reported [stratum value](https://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_strata) of the NTP server - -Use the Endpoint when configuring an NTP client or server. For example: - -```conf -# /etc/ntpsec/ntp.conf -... -server tic.ntp.telstra.net iburst -``` - -## Useful Resources -- https://docs.ntpsec.org/latest/ntp_conf.html -- https://docs.ntpsec.org/latest/ntpdig.html -- https://docs.ntpsec.org/latest/ntpq.html -- bypass isp blocks on port 123 -## Table of Contents -- [ISPs](#ISPs) -- [Organisations](#Organisations) -- [Others](#Others) -- [Universities](#Universities) -## ISPs -Internet Service Providers -### Aussie Broadband -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp-adl.aussiebroadband.com.au|Y||| -|ntp-bne.aussiebroadband.com.au|Y||| -|ntp-mel.aussiebroadband.com.au|Y||| -|ntp-per.aussiebroadband.com.au|Y||| -|ntp-syd.aussiebroadband.com.au|Y||| - -### Exetel -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|clock.exetel.com.au|Y|220.233.0.50|3 - -### Internode -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns2.on.net|Y|192.231.203.2|3 -|ntp.internode.on.net|Y|192.231.203.132|2 -|ntp.on.net|Y|192.231.203.132|2 - -### Optus -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.optusnet.com.au|Y||| -|time01.mel.optus.net|Y|211.31.132.28|2 -|time02.mel.optus.net|Y|211.31.132.29|2 - -### Spintel -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|203.23.237.200|Y|203.23.237.200|2 - -### TPG -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp1.tpg.com.au|Y|203.12.160.2|2 -|ntp2.tpg.com.au|Y|203.26.24.6|2 - -### Telstra -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|chronos.ntp.telstra.net|Y|203.14.0.250|2 -|chronos1.ntp.telstra.net|Y|203.14.0.251|2 -|tic.ntp.telstra.net|Y|203.14.0.250|2 -|toc.ntp.telstra.net|Y|203.14.0.251|2 - -### Vocus -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.vocus.network|Y||| -|ntp01.vic.vocus.network|Y||| -|ntp02.vic.vocus.network|Y|211.26.226.21|2 - -### iPrimus -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.iprimus.com.au|Y||| - -### iiNet -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.ii.net|Y|203.0.178.191|3 -|ntp.iinet.net.au|Y|203.0.178.191|2 -|ntp1.iinet.net.au|Y|203.0.178.191|3 -|ntp2.iinet.net.au|Y|203.0.178.191|3 -|time.iinet.net.au|Y|203.0.178.191|3 - - -## Organisations -Other organisations not under other another category -### APCS -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.apcs.com.au|Y|210.79.26.105|3 - -### ASE IT Networks -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.aseit.com.au|Y||| - -### Aus IT Services -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.aus-it.com.au|Y|103.48.208.254|3 - -### Australia Online -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.australiaonline.net.au|Y||| -|time.australiaonline.net.au|Y||| - -### BitWave Networks -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.bitwave.com.au|Y|103.198.24.6|1 - -### Comvergence -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.comvergence.com.au|Y||| -|time.comvergence.com.au|Y||| - -### Conexim -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.conexim.com.au|Y|203.124.190.53|3 -|ns1.conexim.com.au|Y|203.124.190.53|3 -|time.conexim.com.au|Y||| - -### Cynergic -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns2.cynergic.com.au|Y|203.55.18.5|2 -|ns3.cynergic.com.au|Y|203.55.18.5|2 - -### Dedicated Servers -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.dedicatedservers.net.au|Y|159.196.44.158|2 - -### ECN Internet -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.ecn.net.au|Y|203.22.70.2|3 - -### EscapeNet -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.esc.net.au|Y|203.25.185.252|3 -|tic.esc.net.au|Y|123.136.34.45|3 -|toc.esc.net.au|Y|123.136.34.46|3 - -### FetchTV -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|0.fetchtv.pool.ntp.org|Y|216.229.4.66|2 -|ntp.fetchtv.com.au|Y|212.227.240.160|2 - -### GoHosting -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.gohosting.com.au|Y|103.11.147.150|3 - -### Host Tel -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns0.hosttel.com.au|Y||| -|ns1.hosttel.com.au|Y||| -|ns2.hosttel.com.au|Y||| -|ns4.hosttel.com.au|Y||| -|ntp.hosttel.com.au|N||| - -### Hostworks -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.hostworks.com.au|Y|202.58.63.200|2 - -### Infinite Networks -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.infinite.net.au|Y|175.106.7.2|4 - -### Interconnect Networks -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.rbe.net.au|Y|192.231.203.132|2 - -### Internet Association of Australia -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.asn.au|N||| -|ntp.waia.asn.au|Y||| - -### KERNWIFI -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.kernwifi.com.au|Y|159.196.3.239|1 -|ntp2.kernwifi.com.au|N||| - -### Nexon -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.nexon.com.au|Y|210.215.221.1|3 -|ntp.nexon.com.au|Y|210.215.6.3|2 -|ntp2.nexon.com.au|Y|210.215.221.1|3 - -### Sky News Australia -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.skynews.com.au|Y||| - -### Spectrum Networks -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns2.spectrum.com.au|Y|203.14.108.10|11 -|ntp.spectrum.com.au|Y|202.68.160.8|3 -|time.spectrum.com.au|Y|202.68.160.8|3 - -### Web in a Box -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.webinabox.net.au|Y|110.173.224.100|2 - -### connect.com.au -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.connect.com.au|Y|192.189.54.17|2 -|ntp.mel.connect.com.au|Y|192.189.54.17|2 - - -## Others -Other individual servers not tied to a multi-server organisation -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|syd4gps0.syd.ops.aspac.uu.net|Y|203.166.99.123|1 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|vk6hgr.echidna.id.au|Y|180.150.124.24|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|web02.anfiuwp.org.au|N||| - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|gw.vk6hgr.echidna.id.au|Y|180.150.124.24|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.2000cn.com.au|Y|103.51.68.133|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.mazzanet.net.au|Y|203.206.205.83|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.git.au|Y||| - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.polyfoam.com.au|Y|203.52.62.212|1 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|smtp.juneks.com.au|Y|119.18.6.37|1 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.9r.com.au|Y||| - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.esec.com.au|Y||| - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|mel.clearnet.pw|Y|67.219.100.202|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp1.ds.network|Y|27.124.125.250|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|melbourne.kitten.im|Y|67.219.111.127|1 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|pauseq4vntp1.datamossa.io|Y|103.76.40.123|3 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.tfmcloud.au|Y|103.165.180.123|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|svc4.eshorizon.net|Y|139.99.236.38|3 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|syd.clearnet.pw|Y|139.180.160.82|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|mansfield.id.au|Y|110.232.114.22|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ap-southeast-2.clearnet.pw|Y|194.195.249.28|2 - -### -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp-sydney.gombadi.com|Y|194.195.124.41|2 - - -## Universities -Universities, Colleges, TAFEs, and other related institutions -### Australian Catholic University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.acu.edu.au|Y||| -|ns0.acu.edu.au|Y||| -|ns2.acu.edu.au|Y||| - -### Australian National University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|chronos.anu.edu.au|Y||| -|ns1.anu.edu.au|Y|150.203.1.10|3 -|ns2.anu.edu.au|Y|150.203.22.28|3 -|ns3.anu.edu.au|Y||| -|ns4.anu.edu.au|Y||| -|ntp.anu.edu.au|Y|150.203.1.10|3 -|ntp1.anu.edu.au|Y|150.203.1.10|3 -|ntp2.anu.edu.au|Y|150.203.22.28|3 -|ntp3.anu.edu.au|N||| - -### Avondale University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns0.avondale.edu.au|Y||| -|ns1.avondale.edu.au|Y||| - -### Bond University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.bond.edu.au|Y||| - -### CQ University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.cqu.edu.au|Y||| -|ns2.cqu.edu.au|Y||| -|ntp.cqu.edu.au|Y||| -|ntp1.cqu.edu.au|Y||| -|ntp2.cqu.edu.au|Y||| -|ntp3.cqu.edu.au|Y||| -|ntp4.cqu.edu.au|Y||| - -### Charles Darwin University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.cdu.edu.au|Y||| -|ns2.cdu.edu.au|Y||| -|ntp.cdu.edu.au|Y||| -|ntp1.cdu.edu.au|Y||| -|ntp2.cdu.edu.au|Y||| -|ntp3.cdu.edu.au|Y||| - -### Charles Sturt University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.csu.edu.au|Y||| -|ntp.csu.edu.au|Y||| - -### Christ Church Grammar School (Western Australia) -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|leontp.ccgs.wa.edu.au|Y|203.135.184.123|1 - -### Curtin University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.curtin.edu.au|Y||| -|ns2.curtin.edu.au|Y||| -|ns3.curtin.edu.au|Y||| -|ntp.curtin.edu.au|Y||| -|time.curtin.edu.au|Y||| - -### Deakin University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.deakin.edu.au|Y|128.184.218.53|3 -|ns2.deakin.edu.au|Y|128.184.34.53|3 - -### Edith Cowan University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.ecu.edu.au|Y||| -|ns2.ecu.edu.au|Y||| -|ntp.ecu.edu.au|Y||| -|ntp1.ecu.edu.au|Y||| -|ntp2.ecu.edu.au|Y||| - -### Federation University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.federation.edu.au|Y||| - -### Flinders University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.flinders.edu.au|Y||| - -### Griffith University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.griffith.edu.au|Y|132.234.1.1|3 - -### James Cook University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.jcu.edu.au|N||| -|ns1.jcu.edu.au|Y||| -|ns2.jcu.edu.au|Y||| -|ns3.jcu.edu.au|Y||| -|ns4.jcu.edu.au|Y||| -|ntp.jcu.edu.au|Y||| -|ntp1.jcu.edu.au|Y||| -|ntp2.jcu.edu.au|Y||| - -### LaTrobe University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns0.latrobe.edu.au|Y||| -|ns1.latrobe.edu.au|Y||| -|ns2.latrobe.edu.au|Y||| -|ns3.latrobe.edu.au|Y||| -|ntp.latrobe.edu.au|Y||| -|ntp1.latrobe.edu.au|Y||| -|ntp2.latrobe.edu.au|Y||| -|ntp4.latrobe.edu.au|Y||| - -### Macquarie University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.mq.edu.au|Y||| -|ntp1.mq.edu.au|Y||| -|ntp2.mq.edu.au|Y||| -|ntp3.mq.edu.au|Y||| -|ntp4.mq.edu.au|Y||| -|ntp5.mq.edu.au|Y||| -|time.mq.edu.au|Y||| - -### Monash University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.monash.edu.au|Y||| -|ns2.monash.edu.au|Y||| -|ns3.monash.edu.au|Y||| -|ns4.monash.edu.au|Y||| -|ntp.monash.edu.au|Y||| -|ntp1.monash.edu.au|Y||| -|ntp1.net.monash.edu.au|Y|130.194.1.123|1 -|ntp2.monash.edu.au|Y||| -|ntp2.net.monash.edu.au|Y|130.194.7.123|1 -|time.monash.edu.au|Y||| - -### Murdoch University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.murdoch.edu.au|Y||| -|ns2.murdoch.edu.au|Y||| -|ns3.murdoch.edu.au|Y||| -|ns4.murdoch.edu.au|Y||| -|ntp.murdoch.edu.au|Y||| - -### Queensland University of Technology -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.qut.edu.au|Y||| -|ns2.qut.edu.au|Y||| -|ns3.qut.edu.au|Y||| -|ns4.qut.edu.au|Y||| - -### RMIT University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|time.rmit.edu.au|Y|159.196.44.158|2 - -### Southern Cross University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.scu.edu.au|Y||| - -### Swinburne University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.swin.edu.au|Y||| -|ns2.swin.edu.au|Y||| -|ns3.swin.edu.au|Y||| -|ns4.swin.edu.au|Y||| -|ntp.swin.edu.au|Y|136.186.1.110|2 -|ntp1.swin.edu.au|Y|136.186.1.45|2 -|ntp2.swin.edu.au|Y|136.186.1.80|2 -|ntp3.swin.edu.au|Y|136.186.1.114|2 - -### Torrens University Australia -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | - -### University of Adelaide -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.adelaide.edu.au|Y|129.127.40.3|2 -|ns1.adelaide.edu.au|Y|129.127.43.4|2 -|ns2.adelaide.edu.au|Y|129.127.41.3|2 -|ntp.adelaide.edu.au|Y|129.127.40.3|2 -|ntp1.adelaide.edu.au|Y|129.127.43.4|2 -|ntp2.adelaide.edu.au|Y|129.127.41.3|2 - -### University of Canberra -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns0.canberra.edu.au|Y||| -|ns1.canberra.edu.au|Y||| -|ns2.canberra.edu.au|Y||| -|ntp.canberra.edu.au|Y||| -|ntp1.canberra.edu.au|Y||| -|ntp2.canberra.edu.au|Y||| -|ntp3.canberra.edu.au|Y||| -|ntp4.canberra.edu.au|Y||| - -### University of Divinity -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | - -### University of Melbourne -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.unimelb.edu.au|Y||| -|ns2.unimelb.edu.au|Y||| -|ntp.unimelb.edu.au|Y||| -|ntp1.unimelb.edu.au|Y||| -|ntp2.unimelb.edu.au|Y||| - -### University of New England -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.une.edu.au|Y||| -|ns1.une.edu.au|Y||| -|ns2.une.edu.au|Y||| -|ns3.une.edu.au|Y||| -|ntp.une.edu.au|Y|129.180.118.1|1 -|tick.une.edu.au|Y|129.180.1.14|1 -|tock.une.edu.au|Y|129.180.126.10|1 - -### University of New South Wales -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.unsw.edu.au|Y||| -|ns2.unsw.edu.au|Y||| -|ns3.unsw.edu.au|Y||| -|ntp.unsw.edu.au|Y||| -|ntp1.unsw.edu.au|Y||| -|ntp2.unsw.edu.au|Y||| -|ntp3.unsw.edu.au|Y||| - -### University of Newcastle -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.newcastle.edu.au|Y||| -|ns1.newcastle.edu.au|Y||| -|ns2.newcastle.edu.au|Y||| -|ntp.newcastle.edu.au|Y||| -|time.newcastle.edu.au|Y||| - -### University of Notre Dame Australia -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | - -### University of Queensland -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.uq.edu.au|Y||| -|ntp1.uq.edu.au|Y||| -|ntp2.uq.edu.au|Y||| - -### University of South Australia -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.unisa.edu.au|Y||| -|ns0.unisa.edu.au|Y||| -|ns1.unisa.edu.au|Y||| -|ns2.unisa.edu.au|Y||| - -### University of Southern Queensland -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns0.usq.edu.au|Y||| - -### University of Sydney -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.usyd.edu.au|Y||| -|ntp2.usyd.edu.au|Y||| - -### University of Tasmania -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns1.utas.edu.au|Y||| -|ns2.utas.edu.au|Y||| - -### University of Technology Sydney -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.uts.edu.au|Y||| -|ns1.uts.edu.au|Y||| -|ns2.uts.edu.au|Y||| -|ns3.uts.edu.au|Y||| -|ns4.uts.edu.au|Y||| -|time.uts.edu.au|Y||| - -### University of Western Australia -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.uwa.edu.au|Y||| -|ns1.uwa.edu.au|Y||| -|ns2.uwa.edu.au|Y||| -|ns3.uwa.edu.au|Y||| -|time.uwa.edu.au|Y|130.95.128.36|3 - -### University of Wollongong -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.uow.edu.au|Y||| - -### University of Woolongong -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | - -### University of the Sunshine Coast -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ntp.usc.edu.au|Y|203.29.107.140|2 -|ntp1.usc.edu.au|Y|203.29.107.140|2 -|ntp2.usc.edu.au|Y|203.29.107.141|2 -|ntp3.usc.edu.au|Y|203.57.184.172|2 -|ntp4.usc.edu.au|Y|203.57.184.173|2 - -### Victoria University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | - -### Western Sydney University -| Endpoint | A/AAAA | IP | Stratum | -| :--------------------------------- | -----: | :--------------- | ------: | -|ns.uws.edu.au|Y||| -|ns.westernsydney.edu.au|Y||| -|ns1.uws.edu.au|Y||| -|ns1.westernsydney.edu.au|Y||| -|ns2.uws.edu.au|Y||| -|ns2.westernsydney.edu.au|Y||| -|ns3.uws.edu.au|Y||| -|ns3.westernsydney.edu.au|Y||| -|ns4.uws.edu.au|Y||| -|ns4.westernsydney.edu.au|Y||| -|ntp.uws.edu.au|Y||| -|ntp.westernsydney.edu.au|Y||| -|ntp1.uws.edu.au|Y||| -|ntp2.uws.edu.au|Y||| -|ntp2.westernsydney.edu.au|Y||| -|time.uws.edu.au|Y||| -|time.westernsydney.edu.au|Y||| - - diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/data/lookups.json b/data/lookups.json new file mode 100644 index 0000000..a75489d --- /dev/null +++ b/data/lookups.json @@ -0,0 +1,2587 @@ +[ + { + "name": "Arrow Energy", + "categories": [ "org" ], + "cert": "www.arrowenergy.com.au:443", + "domains": [ + { "name": "arrowenergy.com.au" } + ] + }, + { + "name": "Australian National University", + "categories": [ "university" ], + "cert": "www.anu.edu.au:443", + "domains": [ + { "name": "anu.edu.au" } + ] + }, + { + "name": "Australian Catholic University", + "categories": [ "university" ], + "cert": "www.acu.edu.au:443", + "domains": [ + { "name": "acu.edu.au" } + ] + }, + { + "name": "Avondale University", + "categories": [ "university" ], + "cert": "www.avondale.edu.au:443", + "domains": [ + { "name": "avondale.edu.au" } + ] + }, + { + "name": "Bond University", + "categories": [ "university" ], + "cert": "bond.edu.au:443", + "domains": [ + { "name": "bond.edu.au" } + ] + }, + { + "name": "CQ University", + "categories": [ "university" ], + "cert": "cq.edu.au:443", + "domains": [ + { "name": "cq.edu.au" } + ] + }, + { + "name": "Charles Darwin University", + "categories": [ "university" ], + "cert": "www.cdu.edu.au:443", + "domains": [ + { "name": "cdu.edu.au" } + ] + }, + { + "name": "Charles Sturt University", + "categories": [ "university" ], + "cert": "www.csu.edu.au:443", + "domains": [ + { "name": "csu.edu.au" } + ] + }, + { + "name": "Christ Church Grammar School (Western Australia)", + "categories": [ "university" ], + "endpoints": [ + { "host": "leontp.ccgs.wa.edu.au:123" } + ] + }, + { + "name": "Deakin University", + "categories": [ "university" ], + "cert": "www.deakin.edu.au:443", + "domains": [ + { "name": "deakin.edu.au" } + ] + }, + { + "name": "Edith Cowan University", + "categories": [ "university" ], + "cert": "www.ecu.edu.au:443", + "domains": [ + { "name": "ecu.edu.au" } + ] + }, + { + "name": "Federation University", + "categories": [ "university" ], + "cert": "federation.edu.au:443", + "domains": [ + { "name": "federation.edu.au" } + ] + }, + { + "name": "Griffith University", + "categories": [ "university" ], + "cert": "www.griffith.edu.au:443", + "domains": [ + { "name": "griffith.edu.au" } + ] + }, + { + "name": "James Cook University", + "categories": [ "university" ], + "cert": "www.jcu.edu.au:443", + "domains": [ + { "name": "jcu.edu.au" } + ] + }, + { + "name": "LaTrobe University", + "categories": [ "university" ], + "cert": "www.latrobe.edu.au:443", + "domains": [ + { "name": "latrobe.edu.au" } + ] + }, + { + "name": "Macquarie University", + "categories": [ "university" ], + "cert": "www.mq.edu.au:443", + "domains": [ + { "name": "mq.edu.au" } + ] + }, + { + "name": "Monash University", + "categories": [ "university" ], + "cert": "www.monash.edu.au:443", + "domains": [ + { "name": "monash.edu.au" }, + { "name": "net.monash.edu.au" } + ] + }, + { + "name": "Murdoch University", + "categories": [ "university" ], + "cert": "www.murdoch.edu.au:443", + "domains": [ + { "name": "murdoch.edu.au" } + ] + }, + { + "name": "Queensland University of Technology", + "categories": [ "university" ], + "cert": "www.qut.edu.au:443", + "domains": [ + { "name": "qut.edu.au" } + ] + }, + { + "name": "RMIT University", + "categories": [ "university" ], + "cert": "www.rmit.edu.au:443", + "domains": [ + { "name": "rmit.edu.au" } + ] + }, + { + "name": "Swoop", + "categories": [ "isp" ], + "cert": "www.swoop.com.au:443", + "domains": [ + { "name": "swoop.com.au" } + ] + }, + { + "name": "Southern Cross University", + "categories": [ "university" ], + "cert": "www.scu.edu.au:443", + "domains": [ + { "name": "scu.edu.au" } + ] + }, + { + "name": "Swinburne University", + "categories": [ "university" ], + "cert": "www.swinburne.edu.au:443", + "domains": [ + { "name": "swin.edu.au" } + ] + }, + { + "name": "Torrens University", + "categories": [ "university" ], + "cert": "www.torrens.edu.au:443", + "domains": [ + { "name": "torrens.edu.au" } + ] + }, + { + "name": "University of Adelaide", + "categories": [ "university" ], + "cert": "www.adelaide.edu.au:443", + "domains": [ + { "name": "adelaide.edu.au" } + ] + }, + { + "name": "University of Canberra", + "categories": [ "university" ], + "cert": "www.canberra.edu.au:443", + "domains": [ + { "name": "canberra.edu.au" } + ] + }, + { + "name": "University of Divinity", + "categories": [ "university" ], + "cert": "divinity.edu.au:443", + "domains": [ + { "name": "divinity.edu.au" } + ] + }, + { + "name": "University of Melbourne", + "categories": [ "university" ], + "cert": "www.unimelb.edu.au:443", + "domains": [ + { "name": "unimelb.edu.au" } + ] + }, + { + "name": "University of New England", + "categories": [ "university" ], + "cert": "www.une.edu.au:443", + "domains": [ + { "name": "une.edu.au" } + ] + }, + { + "name": "University of New South Wales", + "categories": [ "university" ], + "cert": "www.unsw.edu.au:443", + "domains": [ + { "name": "unsw.edu.au" } + ] + }, + { + "name": "University of Newcastle", + "categories": [ "university" ], + "cert": "www.newcastle.edu.au:443", + "domains": [ + { "name": "newcastle.edu.au" } + ] + }, + { + "name": "University of Notre Dame Australia", + "categories": [ "university" ], + "cert": "www.notredame.edu.au:443", + "domains": [ + { "name": "notredame.edu.au" } + ] + }, + { + "name": "University of Queensland", + "categories": [ "university" ], + "cert": "www.uq.edu.au:443", + "domains": [ + { "name": "uq.edu.au" } + ] + }, + { + "name": "University of South Australia", + "categories": [ "university" ], + "cert": "www.unisa.edu.au:443", + "domains": [ + { "name": "unisa.edu.au" } + ] + }, + { + "name": "University of Sydney", + "categories": [ "university" ], + "cert": "www.sydney.edu.au:443", + "domains": [ + { "name": "usyd.edu.au" } + ] + }, + { + "name": "University of Tasmania", + "categories": [ "university" ], + "cert": "www.utas.edu.au:443", + "domains": [ + { "name": "utas.edu.au" } + ] + }, + { + "name": "University of Technology Sydney", + "categories": [ "university" ], + "cert": "www.uts.edu.au:443", + "domains": [ + { "name": "uts.edu.au" } + ] + }, + { + "name": "University of Western Australia", + "categories": [ "university" ], + "cert": "www.uwa.edu.au:443", + "domains": [ + { "name": "uwa.edu.au" } + ] + }, + { + "name": "University of Woolongong", + "categories": [ "university" ], + "cert": "www.uow.edu.au:443", + "domains": [ + { "name": "uow.edu.au" } + ] + }, + { + "name": "University of the Sunshine Coast", + "categories": [ "university" ], + "cert": "www.usc.edu.au:443", + "domains": [ + { "name": "usc.edu.au"} + ] + }, + { + "name": "Victoria University", + "categories": [ "university" ], + "cert": "www.vu.edu.au:443", + "domains": [ + { "name": "vu.edu.au" } + ] + }, + { + "name": "Western Sydney University", + "categories": [ "university" ], + "cert": "www.westernsydney.edu.au:443", + "domains": [ + { "name": "uws.edu.au" }, + { "name": "westernsydney.edu.au" } + ] + }, + { + "name": "ABC", + "categories": [ "top" ], + "cert": "www.abc.net.au:443", + "domains": [ + { "name": "abc.net.au" } + ] + }, + { + "name": "Sydney Morning Herald", + "categories": [ "top" ], + "cert": "www.smh.com.au:443", + "domains": [ + { "name": "smh.com.au" } + ] + }, + { + "name": "Victorian Government", + "categories": [ "top" ], + "cert": "www.vic.gov.au:443", + "domains": [ + { "name": "vic.gov.au" } + ] + }, + { + "name": "news.com.au", + "categories": [ "top" ], + "cert": "www.news.com.au:443", + "domains": [ + { "name": "news.com.au" } + ] + }, + { + "name": "New South Wales Government", + "categories": [ "top" ], + "cert": "www.nsw.gov.au:443", + "domains": [ + { "name": "nsw.gov.au" } + ] + }, + { + "name": "Queensland Government", + "categories": [ "top" ], + "cert": "www.qld.gov.au:443", + "domains": [ + { "name": "qld.gov.au" } + ] + }, + { + "name": "The Age", + "categories": [ "top" ], + "cert": "www.theage.com.au:443", + "domains": [ + { "name": "theage.com.au" } + ] + }, + { + "name": "Western Australia Government", + "categories": [ "top" ], + "cert": "www.wa.gov.au:443", + "domains": [ + { "name": "wa.gov.au" } + ] + }, + { + "name": "SBS", + "categories": [ "top" ], + "cert": "www.sbs.com.au:443", + "domains": [ + { "name": "sbs.com.au" } + ] + }, + { + "name": "The Australian", + "categories": [ "top" ], + "cert": "www.theaustralian.com.au:443", + "domains": [ + { "name": "theaustralian.com.au" } + ] + }, + { + "name": "CSIRO", + "categories": [ "top" ], + "cert": "www.csiro.au:443", + "domains": [ + { "name": "csiro.au" } + ] + }, + { + "name": "Brennan IT", + "categories": [ "org" ], + "cert": "www.brennanit.com.au:443", + "domains": [ + { "name": "brennanit.com.au" } + ] + }, + { + "name": "National Library of Australia", + "categories": [ "top" ], + "cert": "www.nla.gov.au:443", + "domains": [ + { "name": "nla.gov.au" } + ] + }, + { + "name": "South Australia Government", + "categories": [ "top" ], + "cert": "www.sa.gov.au:443", + "domains": [ + { "name": "sa.gov.au" } + ] + }, + { + "name": "Amazon Australia", + "categories": [ "top" ], + "cert": "www.amazon.com.au:443", + "domains": [ + { "name": "amazon.com.au" } + ] + }, + { + "name": "eBay Australia", + "categories": [ "top" ], + "cert": "www.ebay.com.au:443", + "domains": [ + { "name": "ebay.com.au" } + ] + }, + { + "name": "Department of Health and Aged Care", + "categories": [ "top" ], + "cert": "www.health.gov.au:443", + "domains": [ + { "name": "health.gov.au" } + ] + }, + { + "name": "The Daily Telegraph", + "categories": [ "top" ], + "cert": "www.dailytelegraph.com.au:443", + "domains": [ + { "name": "dailytelegraph.com.au" } + ] + }, + { + "name": "Pinterest Australia", + "categories": [ "top" ], + "cert": "www.pinterest.com.au:443", + "domains": [ + { "name": "pinterest.com.au" } + ] + }, + { + "name": "The Herald Sun", + "categories": [ "top" ], + "cert": "www.heraldsun.com.au:443", + "domains": [ + { "name": "heraldsun.com.au" } + ] + }, + { + "name": "Department of Home Affairs", + "categories": [ "top" ], + "cert": "www.homeaffairs.gov.au:443", + "domains": [ + { "name": "homeaffairs.gov.au" } + ] + }, + { + "name": "Channel 9", + "categories": [ "top" ], + "cert": "www.nine.com.au:443", + "domains": [ + { "name": "9news.com.au" }, + { "name": "nine.com.au" }, + { "name": "nineforbrands.com.au" } + ] + }, + { + "name": "Australian Bureau of Statistics", + "categories": [ "top" ], + "cert": "www.abs.gov.au:443", + "domains": [ + { "name": "abs.gov.au" } + ] + }, + { + "name": "Tasmanian Government", + "categories": [ "top" ], + "cert": "www.tas.gov.au:443", + "domains": [ + { "name": "tas.gov.au" } + ] + }, + { + "name": "Parliament of Australia", + "categories": [ "top" ], + "cert": "www.aph.gov.au:443", + "domains": [ + { "name": "aph.gov.au" } + ] + }, + { + "name": "Bureau of Meteorology", + "categories": [ "top" ], + "domains": [ + { "name": "bom.gov.au" } + ] + }, + { + "name": "The Courier Mail", + "categories": [ "top" ], + "cert": "www.couriermail.com.au:443", + "domains": [ + { "name": "couriermail.com.au" } + ] + }, + { + "name": "Healthdirect Australia", + "categories": [ "top" ], + "cert": "www.healthdirect.gov.au:443", + "domains": [ + { "name": "healthdirect.gov.au" } + ] + }, + { + "name": "Australian Taxation Office", + "categories": [ "top" ], + "cert": "www.ato.gov.au:443", + "domains": [ + { "name": "ato.gov.au" } + ] + }, + { + "name": "Eventbrite", + "categories": [ "top" ], + "cert": "www.eventbrite.com.au:443", + "domains": [ + { "name": "eventbrite.com.au" } + ] + }, + { + "name": "Gizmodo", + "categories": [ "top" ], + "cert": "www.gizmodo.com.au:443", + "domains": [ + { "name": "gizmodo.com.au" } + ] + }, + { + "name": "Northern Territory Government", + "categories": [ "top" ], + "cert": "nt.gov.au:443", + "domains": [ + { "name": "nt.gov.au" } + ] + }, + { + "name": "The Canberra Times", + "categories": [ "top" ], + "cert": "www.canberratimes.com.au:443", + "domains": [ + { "name": "canberra.com.au" } + ] + }, + { + "name": "Office of the Australian Information Commissioner", + "categories": [ "top" ], + "cert": "www.oaic.gov.au:443", + "domains": [ + { "name": "oaic.gov.au" } + ] + }, + { + "name": "Department of Foreign Affairs and Trade", + "categories": [ "top" ], + "cert": "www.dfat.gov.au:443", + "domains": [ + { "name": "dfat.gov.au" }, + { "name": "embassy.gov.au" } + ] + }, + { + "name": "7News", + "categories": [ "top" ], + "cert": "7news.com.au:443", + "domains": [ + { "name": "7news.com.au" } + ] + }, + { + "name": "Prime Minister of Australia", + "categories": [ "top" ], + "cert": "www.pm.gov.au:443", + "domains": [ + { "name": "pm.gov.au" }, + { "name": "australia.gov.au" } + ] + }, + { + "name": "New South Wales Department of Education", + "categories": [ "top" ], + "cert": "education.nsw.gov.au:443", + "domains": [ + { "name": "education.nsw.gov.au" } + ] + }, + { + "name": "Australasian Legal Information Institute", + "categories": [ "top" ], + "cert": "austlii.edu.au:443", + "domains": [ + { "name": "austlii.edu.au" } + ] + }, + { + "name": "Brisbane Times", + "categories": [ "top" ], + "cert": "www.brisbanetimes.com.au:443", + "domains": [ + { "name": "brisbanetimes.com.au" } + ] + }, + + { + "name": "ACT Government", + "categories": [ "top" ], + "cert": "www.act.gov.au:443", + "domains": [ + { "name": "act.gov.au" } + ] + }, + { + "name": "Federal Register of Legislation", + "categories": [ "top" ], + "cert": "www.legislation.gov.au:443", + "domains": [ + { "name": "legislation.gov.au" } + ] + }, + { + "name": "SEEK", + "categories": [ "top" ], + "cert": "www.seek.com.au:443", + "domains": [ + { "name": "seek.com.au" } + ] + }, + { + "name": "THe West Australian", + "categories": [ "top" ], + "cert": "thewest.com.au:443", + "domains": [ + { "name": "thewest.com.au" }, + { "name": "perthnow.com.au" } + ] + }, + { + "name": "Sky News Australia", + "categories": [ "top" ], + "cert": "www.skynews.com.au:443", + "domains": [ + { "name": "skynews.com.au" } + ] + }, + { + "name": "business.gov.au", + "categories": [ "top" ], + "cert": "business.gov.au:443", + "domains": [ + { "name": "business.gov.au" } + ] + }, + { + "name": "squarealpha", + "categories": [ "org" ], + "cert": "www.squarealpha.com.au:443", + "domains": [ + { "name": "squarealpha.com.au" } + ] + }, + { + "name": "Summit Internet", + "categories": [ "isp" ], + "cert": "summitinternet.com.au:443", + "domains": [ + { "name": "summitinternet.com.au" } + ] + }, + { + "name": "Suncorp", + "categories": [ "org" ], + "cert": "www.suncorp.com.au:443", + "domains": [ + { "name": "suncorp.com.au" } + ] + }, + { + "name": "SwiftFiber", + "categories": [ "isp" ], + "cert": "swiftfiber.com.au:443", + "domains": [ + { "name": "swiftfiber.com.au" } + ] + }, + { + "name": "Sydney Airport", + "categories": [ "org" ], + "cert": "www.sydneyairport.com.au:443", + "domains": [ + { "name": "sydneyairport.com.au" } + ] + }, + { + "name": "QCS Group", + "categories": [ "org" ], + "cert": "qcsgroup.au:443", + "domains": [ + { "name": "qcsgroup.au" } + ] + }, + { + "name": "Aurizon", + "categories": [ "org" ], + "cert": "aurizon.com.au:443", + "domains": [ + { "name": "aurizon.com.au" } + ] + }, + { + "name": "Queensland Rail", + "categories": [ "org" ], + "cert": "www.queenslandrail.com.au:443", + "domains": [ + { "name": "queenslandrail.com.au" } + ] + }, + { + "name": "RACQ", + "categories": [ "org" ], + "cert": "www.racq.com.au:443", + "domains": [ + { "name": "racq.com.au" } + ] + }, + { + "name": "Ramsay Health Care", + "categories": [ "org" ], + "cert": "www.ramsayhealth.com.au:443", + "domains": [ + { "name": "ramsayhealth.com.au" } + ] + }, + { + "name": "R-Group International", + "categories": [ "org" ], + "cert": "r-group.com.au:443", + "domains": [ + { "name": "r-group.com.au" } + ] + }, + { + "name": "ReadiiTel", + "categories": [ "org" ], + "cert": "readiitel.com.au:443", + "domains": [ + { "name": "readiitel.com.au" } + ] + }, + { + "name": "real world technology solutions", + "categories": [ "org" ], + "cert": "rwts.com.au:443", + "domains": [ + { "name": "rwts.com.au" } + ] + }, + { + "name": "realestate.com.au", + "categories": [ "top" ], + "cert": "www.realestate.com.au:443", + "domains": [ + { "name": "realestate.com.au" } + ] + }, + { + "name": "Australain Competition & Consumer Commission", + "categories": [ "top" ], + "cert": "www.accc.gov.au:443", + "domains": [ + { "name": "accc.gov.au" } + ] + }, + { + "name": "Australian Securities & Investments Commission", + "categories": [ "top" ], + "cert": "asic.gov.au:443", + "domains": [ + { "name": "asic.gov.au" } + ] + }, + { + "name": "Department of Climate Change, Energy, the Environment and Water", + "categories": [ "top" ], + "cert": "www.dcceew.gov.au:443", + "domains": [ + { "name": "dcceew.gov.au" } + ] + }, + { + "name": "WJ Partners", + "categories": [ "top" ], + "cert": "wjpartners.com.au:443", + "domains": [ + { "name": "wjpartners.com.au" } + ] + }, + { + "name": "The Advertiser", + "categories": [ "top" ], + "cert": "www.adelaidenow.com.au:443", + "domains": [ + { "name": "adelaidenow.com.au" } + ] + }, + { + "name": "Australia Post", + "categories": [ "top" ], + "cert": "auspost.com.au:443", + "domains": [ + { "name": "auspost.com.au" } + ] + }, + { + "name": "Western Australia Department of Education", + "categories": [ "top" ], + "cert": "www.education.wa.edu.au:443", + "domains": [ + { "name": "education.wa.edu.au" } + ] + }, + { + "name": "GoldNet", + "categories": [ "org" ], + "domains": [ + { "name": "gold.net.au" } + ] + }, + { + "name": "GPK Computers", + "categories": [ "org" ], + "cert": "www.gpkgroup.com.au:443", + "domains": [ + { "name": "gpkgroup.com.au" } + ] + }, + { + "name": "Reserve Bank of Australia", + "categories": [ "top" ], + "cert": "www.rba.gov.au:443", + "domains": [ + { "name": "rba.gov.au" } + ] + }, + { + "name": "Dicker Data", + "categories": [ "org" ], + "cert": "www.dickerdata.com.au:443", + "domains": [ + { "name": "dickerdata.com.au" } + ] + }, + { + "name": "Delion", + "categories": [ "org" ], + "cert": "www.delion.com.au:443", + "domains": [ + { "name": "delion.com.au" } + ] + }, + { + "name": "Data Express", + "categories": [ "org" ], + "cert": "www.dataexpress.net.au:443", + "domains": [ + { "name": "dataexpress.net.au" } + ] + }, + { + "name": "Ethan Group", + "categories": [ "org" ], + "cert": "ethan.global:443", + "domains": [ + { "name": "ethan.global" } + ] + }, + { + "name": "DC West", + "categories": [ "org" ], + "cert": "dcwest.net.au:443", + "domains": [ + { "name": "dcwest.net.au" } + ] + }, + { + "name": "Digital Pacific Australia", + "categories": [ "org" ], + "cert": "www.digitalpacific.com.au:443", + "domains": [ + { "name": "digitalpacific.com.au" } + ] + }, + { + "name": "Daraco IT Services", + "categories": [ "org" ], + "cert": "www.daraco.com.au:443", + "domains": [ + { "name": "daraco.com.au" } + ] + }, + { + "name": "Data Centre as a Service", + "categories": [ "org" ], + "cert": "dcaas.com.au:443", + "domains": [ + { "name": "dcaas.com.au" } + ] + }, + { + "name": "CNT Corp", + "categories": [ "org" ], + "cert": "www.cntcorp.com.au:443", + "domains": [ + { "name": "cntcorp.com.au" } + ] + }, + { + "name": "Beyond Blue", + "categories": [ "top" ], + "cert": "www.beyondblue.org.au:443", + "domains": [ + { "name": "beyondblue.org.au" } + ] + }, + { + "name": "Australian Institute of Health and Welfare", + "categories": [ "top" ], + "cert": "www.aihw.gov.au:443", + "domains": [ + { "name": "aihw.gov.au" } + ] + }, + { + "name": "Drive", + "categories": [ "top" ], + "cert": "www.drive.com.au:443", + "domains": [ + { "name": "drive.com.au" } + ] + }, + { + "name": "raisingchildren.net.au", + "categories": [ "top" ], + "cert": "raisingchildren.net.au:443", + "domains": [ + { "name": "raisingchildren.net.au" } + ] + }, + { + "name": "harbour isp", + "categories": [ "isp" ], + "cert": "harbourisp.com.au:443", + "domains": [ + { "name": "harbourisp.com.au" } + ] + }, + { + "name": "iseek", + "categories": [ "org" ], + "cert": "iseek.com.au:443", + "domains": [ + { "name": "iseek.com.au" } + ] + }, + { + "name": "Heritage Bank", + "categories": [ "org" ], + "cert": "www.heritage.com.au:443", + "domains": [ + { "name": "heritage.com.au" } + ] + }, + { + "name": "Therapeutic Goods Administration", + "categories": [ "top" ], + "cert": "www.tga.gov.au:443", + "domains": [ + { "name": "tga.gov.au" } + ] + }, + { + "name": "Fox Sports Australia", + "categories": [ "top" ], + "cert": "www.foxsports.com.au:443", + "domains": [ + { "name": "foxsports.com.au" } + ] + }, + { + "name": "Domain", + "categories": [ "top" ], + "cert": "www.domain.com.au:443", + "domains": [ + { "name": "domain.com.au" } + ] + }, + { + "name": "Broadband Solutions", + "categories": [ "org" ], + "cert": "broadbandsolutions.com.au:443", + "domains": [ + { "name": "broadbandsolutions.com.au" } + ] + }, + { + "name": "Canon Australia", + "categories": [ "org" ], + "cert": "www.canon.com.au:443", + "domains": [ + { "name": "canon.com.au" } + ] + }, + { + "name": "Caznet", + "categories": [ "org" ], + "cert": "caznet.com.au:443", + "domains": [ + { "name": "caznet.com.au" } + ] + }, + { + "name": "CEnet", + "categories": [ "org" ], + "cert": "cenet.catholic.edu.au:443", + "domains": [ + { "name": "cenet.catholic.edu.au" } + ] + }, + { + "name": "Centra Networks", + "categories": [ "org" ], + "cert": "www.centra.com.au:443", + "domains": [ + { "name": "centra.com.au" } + ] + }, + { + "name": "Centorrino Technologies", + "categories": [ "org" ], + "cert": "www.ct.com.au:443", + "domains": [ + { "name": "ct.com.au" } + ] + }, + { + "name": "Aussie Broadband", + "categories": [ "isp" ], + "cert": "www.aussiebroadband.com.au:443", + "domains": [ + { "name": "aussiebroadband.com.au" } + ], + "endpoints": [ + { "host": "ntp-adl.aussiebroadband.com.au:123" }, + { "host": "ntp-bne.aussiebroadband.com.au:123" }, + { "host": "ntp-mel.aussiebroadband.com.au:123" }, + { "host": "ntp-per.aussiebroadband.com.au:123" }, + { "host": "ntp-syd.aussiebroadband.com.au:123" } + ] + }, + { + "name": "Exetel", + "categories": [ "isp" ], + "cert": "www.exetel.com.au:443", + "domains": [ + { "name": "exetel.com.au" } + ] + }, + { + "name": "Internode", + "categories": [ "isp" ], + "cert": "www.internode.on.net:443", + "domains": [ + { "name": "on.net" }, + { "name": "internode.on.net" } + ] + }, + { + "name": "Opticomm", + "categories": [ "org" ], + "cert": "www.opticomm.com.au:443", + "domains": [ + { "name": "opticomm.com.au" } + ] + }, + { + "name": "Optus", + "categories": [ "isp" ], + "cert": "www.optus.com.au:443", + "domains": [ + { "name": "optus.com.au" }, + { "name": "optusnet.com.au" }, + { "name": "optus.net" }, + { "name": "mel.optus.net" } + ] + }, + { + "name": "Spintel", + "categories": [ "isp" ], + "cert": "www.spintel.net.au:443", + "domains": [ + { "name": "spintel.net.au" } + ], + "endpoints": [ + { "host": "203.23.237.200:123" } + ] + }, + { + "name": "WebVault", + "categories": [ "org" ], + "cert": "webvault.com.au:443", + "domains": [ + { "name": "webvault.com.au" } + ] + }, + { + "name": "Wagner Corporation", + "categories": [ "org" ], + "cert": "www.wagnercorporation.com.au:443", + "domains": [ + { "name": "wagnercorporation.com.au" } + ] + }, + { + "name": "Westpac", + "categories": [ "org" ], + "cert": "www.westpac.com.au:443", + "domains": [ + { "name": "westpac.com.au" } + ] + }, + { + "name": "Wireline", + "categories": [ "org" ], + "cert": "wireline.com.au:443", + "domains": [ + { "name": "wireline.com.au" } + ] + }, + { + "name": "United IP", + "categories": [ "org" ], + "cert": "unitedip.net.au:443", + "domains": [ + { "name": "unitedip.net.au" } + ] + }, + { + "name": "URL Networks", + "categories": [ "org" ], + "cert": "url.net.au:443", + "domains": [ + { "name": "url.net.au" } + ] + }, + { + "name": "Valve Networks", + "categories": [ "isp" ], + "cert": "valvenetworks.com.au:443", + "domains": [ + { "name": "valvenetworks.com.au" } + ] + }, + { + "name": "Vernet", + "categories": [ "org" ], + "cert": "www.vernet.com.au:443", + "domains": [ + { "name": "vernet.com.au" } + ] + }, + { + "name": "Vine Networks", + "categories": [ "isp" ], + "cert": "vinenetworks.com.au:443", + "domains": [ + { "name": "vinenetworks.com.au" } + ] + }, + { + "name": "Virtutel", + "categories": [ "org" ], + "cert": "www.virtutel.com.au:443", + "domains": [ + { "name": "virtutel.com.au" } + ] + }, + { + "name": "VMvault", + "categories": [ "org" ], + "cert": "vmvault.com.au:443", + "domains": [ + { "name": "vmvault.com.au" } + ] + }, + { + "name": "Somerville Group", + "categories": [ "org" ], + "cert": "store.somerville.com.au:443", + "domains": [ + { "name": "somerville.com.au" } + ] + }, + { + "name": "TI Systems", + "categories": [ "org" ], + "cert": "tisystems.com.au:443", + "domains": [ + { "name": "tisystems.com.au" } + ] + }, + { + "name": "Vodafone Australia", + "categories": [ "org" ], + "cert": "www.vodafone.com.au:443", + "domains": [ + { "name": "vodafone.com.au" } + ] + }, + { + "name": "felix mobile", + "categories": [ "org" ], + "cert": "felixmobile.com.au:443", + "domains": [ + { "name": "felixmobile.com.au" } + ] + }, + { + "name": "Lebara", + "categories": [ "org" ], + "cert": "www.lebara.com.au:443", + "domains": [ + { "name": "lebara.com.au" } + ] + }, + { + "name": "TPG Telecom", + "categories": [ "isp" ], + "cert": "www.tpgtelecom.com.au:443", + "domains": [ + { "name": "tpgtelecom.com.au" } + ] + }, + { + "name": "TPG", + "categories": [ "isp" ], + "cert": "www.tpg.com.au:443", + "domains": [ + { "name": "tpg.com.au" } + ] + }, + { + "name": "Telstra", + "categories": [ "isp" ], + "cert": "www.telstra.com.au:443", + "domains": [ + { "name": "ntp.telstra.net" }, + { "name": "telstra.com.au" } + ] + }, + { + "name": "Vocus", + "categories": [ "isp" ], + "cert": "www.vocus.com.au:443", + "domains": [ + { "name": "vocus.com.au" }, + { "name": "vocus.network" }, + { "name": "vic.vocus.network" } + ] + }, + { + "name": "iPrimus", + "categories": [ "isp" ], + "cert": "www.iprimus.com.au:443", + "domains": [ + { "name": "iprimus.com.au" } + ] + }, + { + "name": "iiNet", + "categories": [ "isp" ], + "cert": "www.iinet.net.au:443", + "domains": [ + { "name": "iinet.net.au" }, + { "name": "ii.net" } + ] + }, + { + "name": "fluccs", + "categories": [ "org" ], + "cert": "www.fluccs.com.au:443", + "domains": [ + { "name": "fluccs.com.au" } + ] + }, + { + "name": "Flintel", + "categories": [ "org" ], + "cert": "flintel.com.au:443", + "domains": [ + { "name": "flintel.com.au" } + ] + }, + { + "name": "FireNet", + "categories": [ "isp" ], + "cert": "firenet.com.au:443", + "domains": [ + { "name": "firenet.com.au" } + ] + }, + { + "name": "fibervision networks", + "categories": [ "isp" ], + "cert": "fibervision.com.au:443", + "domains": [ + { "name": "fibervision.com.au" } + ] + }, + { + "name": "1platform", + "categories": [ "org" ], + "cert": "virtualplatform.com.au:443", + "domains": [ + { "name": "virtualplatform.com.au" } + ] + }, + { + "name": "cre.ative IT", + "categories": [ "org" ], + "cert": "www.creativeit.net.au:443", + "domains": [ + { "name": "creativeit.net.au" } + ] + }, + { + "name": "CorpCloud", + "categories": [ "org" ], + "cert": "www.corpcloud.com.au:443", + "domains": [ + { "name": "corpcloud.com.au" } + ] + }, + { + "name": "5G Networks", + "categories": [ "org" ], + "cert": "5gnetworks.au:443", + "domains": [ + { "name": "5gnetworks.au" } + ] + }, + { + "name": "AARNet", + "categories": [ "org" ], + "cert": "www.aarnet.edu.au:443", + "domains": [ + { "name": "aarnet.edu.au" } + ] + }, + { + "name": "AC3", + "categories": [ "org" ], + "cert": "ac3.com.au:443", + "domains": [ + { "name": "ac3.com.au" } + ] + }, + { + "name": "Acurus Networks", + "categories": [ "org" ], + "cert": "acurus.com.au:443", + "domains": [ + { "name": "acurus.com.au" } + ] + }, + { + "name": "APCS", + "categories": [ "org" ], + "domains": [ + { "name": "apcs.com.au" } + ] + }, + { + "name": "ASE IT Networks", + "categories": [ "org" ], + "domains": [ + { "name": "aseit.com.au" } + ] + }, + { + "name": "AUSGRID", + "categories": [ "org" ], + "cert": "www.ausgrid.com.au:443", + "domains": [ + { "name": "ausgrid.com.au" } + ] + }, + { + "name": "AVCOMM", + "categories": [ "org" ], + "cert": "avcomm.com.au:443", + "domains": [ + { "name": "avcomm.com.au" } + ] + }, + { + "name": "Aus IT Services", + "categories": [ "org" ], + "domains": [ + { "name": "aus-it.com.au" } + ] + }, + { + "name": "Australia Online", + "categories": [ "org" ], + "domains": [ + { "name": "australiaonline.net.au" } + ] + }, + { + "name": "BitWave Networks", + "categories": [ "org" ], + "cert": "bitwave.com.au:443", + "domains": [ + { "name": "bitwave.com.au" } + ] + }, + { + "name": "BluePackets", + "categories": [ "org" ], + "cert": "www.bluepackets.com.au:443", + "domains": [ + { "name": "bluepackets.com.au" } + ] + }, + { + "name": "Christie Networks", + "categories": [ "org" ], + "cert": "christienetworks.com.au:443", + "domains": [ + { "name": "christienetworks.com.au" } + ] + }, + { + "name": "Comvergence", + "categories": [ "org" ], + "domains": [ + { "name": "comvergence.com.au" } + ] + }, + { + "name": "Conexim Australia Pty Ltd", + "categories": [ "org" ], + "domains": [ + { "name": "conexim.com.au" } + ] + }, + { + "name": "Cynergic", + "categories": [ "org" ], + "cert": "cynergic.com.au:443", + "domains": [ + { "name": "cynergic.com.au" } + ] + }, + { + "name": "Crucial Paradigm (Australia)", + "categories": [ "org" ], + "cert": "www.crucial.com.au:443", + "domains": [ + { "name": "crucial.com.au" } + ] + }, + { + "name": "CWNet Australia", + "categories": [ "org" ], + "cert": "cwnet.com.au:443", + "domains": [ + { "name": "cwnet.com.au" } + ] + }, + { + "name": "Dedicated Servers", + "categories": [ "org" ], + "domains": [ + { "name": "dedicatedservers.net.au" } + ] + }, + { + "name": "ECN Internet", + "categories": [ "org" ], + "domains": [ + { "name": "ecn.net.au" } + ] + }, + { + "name": "EscapeNet", + "categories": [ "org" ], + "domains": [ + { "name": "esc.net.au" } + ] + }, + { + "name": "FirstFocus", + "categories": [ "org" ], + "cert": "www.firstfocus.com.au:443", + "domains": [ + { "name": "firstfocus.com.au" } + ] + }, + { + "name": "Encoo Communications", + "categories": [ "org" ], + "cert": "www.encoo.com.au:443", + "domains": [ + { "name": "encoo.com.au" } + ] + }, + { + "name": "Enablis", + "categories": [ "org" ], + "cert": "www.enablis.com.au:443", + "domains": [ + { "name": "enablis.com.au" } + ] + }, + { + "name": "Capti Networks", + "categories": [ "org" ], + "cert": "capti.com.au:443", + "domains": [ + { "name": "capti.com.au" } + ] + }, + { + "name": "Falcore", + "categories": [ "org" ], + "cert": "falcore.com.au:443", + "domains": [ + { "name": "falcore.com.au" } + ] + }, + { + "name": "fastrack technology", + "categories": [ "org" ], + "cert": "www.fastrack.technology:443", + "domains": [ + { "name": "fastrack.technology" } + ] + }, + { + "name": "FetchTV", + "categories": [ "org" ], + "cert": "www.fetchtv.com.au:443", + "domains": [ + { "name": "fetchtv.com.au" } + ], + "endpoints": [ + { "host": "0.fetchtv.pool.ntp.org:123" } + ] + }, + { + "name": "GoHosting", + "categories": [ "org" ], + "cert": "gohosting.com.au:443", + "domains": [ + { "name": "gohosting.com.au" } + ] + }, + { + "name": "Host Tel", + "categories": [ "org" ], + "cert": "hosttel.com.au:443", + "domains": [ + { "name": "hosttel.com.au" } + ] + }, + { + "name": "Lumity Technology Solutions", + "categories": [ "org" ], + "cert": "lumity.com.au:443", + "domains": [ + { "name": "lumity.com.au" } + ] + }, + { + "name": "Leaptel", + "categories": [ "isp" ], + "cert": "leaptel.com.au:443", + "domains": [ + { "name": "leaptel.com.au" } + ] + }, + { + "name": "efex", + "categories": [ "org" ], + "cert": "www.efex.com.au:443", + "domains": [ + { "name": "efex.com.au" } + ] + }, + { + "name": "kinetix", + "categories": [ "isp" ], + "cert": "kinetix.net.au:443", + "domains": [ + { "name": "kinetix.net.au" } + ] + }, + { + "name": "Connect Tel Australia", + "categories": [ "org" ], + "cert": "www.connecttel.com.au:443", + "domains": [ + { "name": "connecttel.com.au" } + ] + }, + { + "name": "JEM", + "categories": [ "org" ], + "cert": "www.jem.com.au:443", + "domains": [ + { "name": "jem.com.au" } + ] + }, + { + "name": "lumea", + "categories": [ "org" ], + "cert": "www.lumea.com.au:443", + "domains": [ + { "name": "lumea.com.au" } + ] + }, + { + "name": "OCCOM", + "categories": [ "isp" ], + "cert": "occom.com.au:443", + "domains": [ + { "name": "occom.com.au" } + ] + }, + { + "name": "mdg it", + "categories": [ "org" ], + "cert": "www.mdg-it.com.au:443", + "domains": [ + { "name": "mdg-it.com.au" } + ] + }, + { + "name": "Mammoth Cloud", + "categories": [ "org" ], + "cert": "www.mammoth.com.au:443", + "domains": [ + { "name": "mammoth.com.au" } + ] + }, + { + "name": "MarchNet", + "categories": [ "org" ], + "cert": "marchnet.com.au:443", + "domains": [ + { "name": "marchnet.com.au" } + ] + }, + { + "name": "Mater", + "categories": [ "org" ], + "cert": "www.mater.org.au:443", + "domains": [ + { "name": "mater.org.au" } + ] + }, + { + "name": "Melbourne ISP", + "categories": [ "isp" ], + "cert": "melbourneisp.com:443", + "domains": [ + { "name": "melbourneisp.com" } + ] + }, + { + "name": "ME Bank", + "categories": [ "org" ], + "cert": "www.mebank.com.au:443", + "domains": [ + { "name": "mebank.com.au" } + ] + }, + { + "name": "Mitsubishi Motors Australia", + "categories": [ "org" ], + "cert": "www.mitsubish-motors.com.au:443", + "domains": [ + { "name": "mitsubishi-motors.com.au" } + ] + }, + { + "name": "MyNet", + "categories": [ "org" ], + "cert": "www.mynet.au:443", + "domains": [ + { "name": "mynet.au" } + ] + }, + { + "name": "NAB Investment Holdings", + "categories": [ "org" ], + "cert": "nabih.com.au:443", + "domains": [ + { "name": "nabih.com.au" } + ] + }, + { + "name": "John Holland", + "categories": [ "org" ], + "cert": "johnholland.com.au:443", + "domains": [ + { "name": "johnholland.com.au" } + ] + }, + { + "name": "Latrobe Community Health Service", + "categories": [ "org" ], + "cert": "www.lchs.com.au:443", + "domains": [ + { "name": "lchs.com.au" } + ] + }, + { + "name": "Launtel", + "categories": [ "isp" ], + "cert": "www.launtel.net.au:443", + "domains": [ + { "name": "launtel.net.au" } + ] + }, + { + "name": "Infinite Networks", + "categories": [ "org" ], + "cert": "www.infinite.net.au:443", + "domains": [ + { "name": "infinite.net.au" } + ] + }, + { + "name": "e-vision", + "categories": [ "org" ], + "cert": "e-vision.com.au:443", + "domains": [ + { "name": "e-vision.com.au" } + ] + }, + { + "name": "CITEC", + "categories": [ "org" ], + "cert": "services.citec.com.au:443", + "domains": [ + { "name": "citec.com.au" }, + { "name": "services.citec.com.au" } + ] + }, + { + "name": "City Communications", + "categories": [ "org" ], + "cert": "citycomms.com.au:443", + "domains": [ + { "name": "citycomms.com.au" } + ] + }, + { + "name": "iag", + "categories": [ "org" ], + "cert": "www.iag.com.au:443", + "domains": [ + { "name": "iag.com.au" } + ] + }, + { + "name": "interphone", + "categories": [ "isp" ], + "cert": "www.interphone.com.au:443", + "domains": [ + { "name": "interphone.com.au" } + ] + }, + { + "name": "IPTelco", + "categories": [ "org" ], + "cert": "iptelco.com.au:443", + "domains": [ + { "name": "iptelco.com.au" } + ] + }, + { + "name": "IPNG", + "categories": [ "org" ], + "cert": "ipng.com.au:443", + "domains": [ + { "name": "ipng.com.au" } + ] + }, + { + "name": "iQNet", + "categories": [ "org" ], + "cert": "iqnet.com.au:443", + "domains": [ + { "name": "iqnet.com.au" } + ] + }, + { + "name": "Terrerent", + "categories": [ "org" ], + "cert": "tesserent.com:443", + "domains": [ + { "name": "tesserent.com" } + ] + }, + { + "name": "Coates Hire", + "categories": [ "org" ], + "cert": "www.coates.com.au:443", + "domains": [ + { "name": "coates.com.au" } + ] + }, + { + "name": "CommSol", + "categories": [ "org" ], + "cert": "commsol.net.au:443", + "domains": [ + { "name": "commsol.net.au" } + ] + }, + { + "name": "Transport for NSW", + "categories": [ "org" ], + "cert": "www.transport.nsw.gov.au:443", + "domains": [ + { "name": "transport.nsw.gov.au" } + ] + }, + { + "name": "IP Exchange", + "categories": [ "org" ], + "cert": "ipexchange.com.au:443", + "domains": [ + { "name": "ipexchange.com.au" } + ] + }, + { + "name": "TAFE NSW", + "categories": [ "org" ], + "cert": "www.tafensw.edu.au:443", + "domains": [ + { "name": "tafensw.edu.au" } + ] + }, + { + "name": "Talk To You Soon", + "categories": [ "org" ], + "cert": "ttys.com.au:443", + "domains": [ + { "name": "ttys.com.au" } + ] + }, + { + "name": "TechPath", + "categories": [ "org" ], + "cert": "www.techpath.com.au:443", + "domains": [ + { "name": "techpath.com.au" } + ] + }, + { + "name": "Telair", + "categories": [ "isp" ], + "cert": "www.telair.com.au:443", + "domains": [ + { "name": "telair.com.au" } + ] + }, + { + "name": "Telco in a Box", + "categories": [ "org" ], + "cert": "www.telcoinabox.com.au:443", + "domains": [ + { "name": "telcoinabox.com.au" } + ] + }, + { + "name": "tello", + "categories": [ "isp" ], + "cert": "www.tello.com.au:443", + "domains": [ + { "name": "tello.com.au" } + ] + }, + { + "name": "The Missing Link", + "categories": [ "org" ], + "cert": "www.themissinglink.com.au:443", + "domains": [ + { "name": "themissinglink.com.au" } + ] + }, + { + "name": "Screwloose IT Solutions", + "categories": [ "org" ], + "cert": "screwlooseit.com.au:443", + "domains": [ + { "name": "screwloose.com.au" } + ] + }, + { + "name": "Sensor Dynamics", + "categories": [ "org" ], + "cert": "sensordynamics.com.au:443", + "domains": [ + { "name": "sensordynamics.com.au" } + ] + }, + { + "name": "Sentrian", + "categories": [ "org" ], + "cert": "www.sentrian.com.au:443", + "domains": [ + { "name": "sentrian.com.au" } + ] + }, + { + "name": "Servers Australia", + "categories": [ "org" ], + "cert": "www.serversaustralia.com.au:443", + "domains": [ + { "name": "serversaustralia.com.au" } + ] + }, + { + "name": "Cloud Servers Australia", + "categories": [ "org" ], + "cert": "www.cloudserversaustralia.com.au:443", + "domains": [ + { "name": "cloudserversaustralia.com.au" } + ] + }, + { + "name": "Cloud365 Australia", + "categories": [ "org" ], + "cert": "cloud365.com.au:443", + "domains": [ + { "name": "cloud365.com.au" } + ] + }, + { + "name": "Interconnect Networks", + "categories": [ "org" ], + "domains": [ + { "name": "rbe.net.au" } + ] + }, + { + "name": "ConnektNet", + "categories": [ "org" ], + "cert": "connektnet.com.au:443", + "domains": [ + { "name": "connektnet.com.au" } + ] + }, + { + "name": "Internet Association of Australia", + "categories": [ "org" ], + "domains": [ + { "name": "asn.au" }, + { "name": "waia.asn.au" }, + { "name": "internet.asn.au" } + ] + }, + { + "name": "ICTouch", + "categories": [ "org" ], + "cert": "www.ictouch.com.au:443", + "domains": [ + { "name": "ictouch.com.au" } + ] + }, + { + "name": "Host Networks", + "categories": [ "org" ], + "cert": "hostnetworks.com.au:443", + "domains": [ + { "name": "hostnetworks.com.au" } + ] + }, + { + "name": "Host Universal", + "categories": [ "org" ], + "cert": "hostuniversal.com.au:443", + "domains": [ + { "name": "hostuniversal.com.au" } + ] + }, + { + "name": "hostaway", + "categories": [ "org" ], + "cert": "www.hostaway.net.au:443", + "domains": [ + { "name": "hostaway.net.au" } + ] + }, + { + "name": "HostedNetwork", + "categories": [ "org" ], + "cert": "www.hostednetwork.com.au:443", + "domains": [ + { "name": "hostednetwork.com.au" } + ] + }, + { + "name": "Hunter Water", + "categories": [ "org" ], + "cert": "www.hunterwater.com.au:443", + "domains": [ + { "name": "hunterwater.com.au" } + ] + }, + { + "name": "hyperwave", + "categories": [ "isp" ], + "cert": "www.hyperwave.com.au:443", + "domains": [ + { "name": "hyperwave.com.au" } + ] + }, + { + "name": "Canary Technology Solutions", + "categories": [ "org" ], + "cert": "www.canaryit.com.au:443", + "domains": [ + { "name": "canaryit.com.au" } + ] + }, + { + "name": "gigafy", + "categories": [ "org" ], + "cert": "gigafy.com.au:443", + "domains": [ + { "name": "gigafy.com.au" } + ] + }, + { + "name": "gigawave", + "categories": [ "isp" ], + "cert": "gigawave.com.au:443", + "domains": [ + { "name": "gigawave.com.au" } + ] + }, + { + "name": "gippswifi", + "categories": [ "org" ], + "cert": "www.gippswifi.com.au:443", + "domains": [ + { "name": "gippswifi.com.au" } + ] + }, + { + "name": "Bandwidth Holdings", + "categories": [ "org" ], + "cert": "bwholdings.com.au:443", + "domains": [ + { "name": "bwholdings.com.au" } + ] + }, + { + "name": "Bendigo Telco", + "categories": [ "org" ], + "cert": "www.bendigotelco.com.au:443", + "domains": [ + { "name": "bendigotelco.com.au" } + ] + }, + { + "name": "KERNWIFI", + "categories": [ "org" ], + "domains": [ + { "name": "kernwifi.com.au" } + ] + }, + { + "name": "RemoteISP", + "categories": [ "isp" ], + "cert": "remoteisp.com.au:443", + "domains": [ + { "name": "remoteisp.com.au" } + ] + }, + { + "name": "Reseau", + "categories": [ "org" ], + "cert": "reseau.com.au:443", + "domains": [ + { "name": "reseau.com.au" } + ] + }, + { + "name": "Rising Sun Pictures", + "categories": [ "org" ], + "cert": "www.rsp.com.au:443", + "domains": [ + { "name": "rsp.com.au" } + ] + }, + { + "name": "Pentanet", + "categories": [ "isp" ], + "cert": "pentanet.com.au:443", + "domains": [ + { "name": "pentanet.com.au" } + ] + }, + { + "name": "pingco", + "categories": [ "org" ], + "cert": "pingco.com.au:443", + "domains": [ + { "name": "pingco.com.au" } + ] + }, + { + "name": "Pivit", + "categories": [ "org" ], + "cert": "pivit.com.au:443", + "domains": [ + { "name": "pivit.com.au" } + ] + }, + { + "name": "Premier Technology Solutions", + "categories": [ "org" ], + "cert": "www.premiertech.com.au:443", + "domains": [ + { "name": "premiertech.com.au" } + ] + }, + { + "name": "Prodigy Communications", + "categories": [ "org" ], + "cert": "www.prodigy.com.au:443", + "domains": [ + { "name": "prodigy.com.au" } + ] + }, + { + "name": "On Q Communications", + "categories": [ "isp" ], + "cert": "onq.com.au:443", + "domains": [ + { "name": "onq.com.au" } + ] + }, + { + "name": "Clearstream Broadband", + "categories": [ "org" ], + "cert": "clearstream.com.au:443", + "domains": [ + { "name": "clearstream.com.au" } + ] + }, + { + "name": "OntheNet", + "categories": [ "isp" ], + "cert": "www.onthenet.com.au:443", + "domains": [ + { "name": "onthenet.com.au" } + ] + }, + { + "name": "Optitel", + "categories": [ "org" ], + "cert": "www.optitel.com.au:443", + "domains": [ + { "name": "optitel.com.au" } + ] + }, + { + "name": "OvertheWire", + "categories": [ "org" ], + "cert": "overthewire.com.au:443", + "domains": [ + { "name": "overthewire.com.au" } + ] + }, + { + "name": "Ozot", + "categories": [ "isp"], + "cert": "ozot.com.au:443", + "domains": [ + { "name": "ozot.com.au" } + ] + }, + { + "name": "NEC", + "categories": [ "org" ], + "cert": "www.nec.com.au:443", + "domains": [ + { "name": "nec.com.au" } + ] + }, + { + "name": "net360", + "categories": [ "org" ], + "cert": "net360.com.au:443", + "domains": [ + { "name": "net360.com.au" } + ] + }, + { + "name": "netier", + "categories": [ "org" ], + "cert": "www.netier.com.au:443", + "domains": [ + { "name": "netier.com.au" } + ] + }, + { + "name": "Newcastle Connect", + "categories": [ "org" ], + "cert": "newcastleconnect.com.au:443", + "domains": [ + { "name": "newcastleconnect.com.au" } + ] + }, + { + "name": "nexthop", + "categories": [ "org" ], + "cert": "www.nexthop.com.au:443", + "domains": [ + { "name": "nexthop.com.au" } + ] + }, + { + "name": "Nexon", + "categories": [ "org" ], + "cert": "nexon.com.au:443", + "domains": [ + { "name": "nexon.com.au" } + ] + }, + { + "name": "Shine Lawyers", + "categories": [ "org" ], + "cert": "www.shine.com.au:443", + "domains": [ + { "name": "shine.com.au" } + ] + }, + { + "name": "Simm IT", + "categories": [ "org" ], + "cert": "simmit.com.au:443", + "domains": [ + { "name": "simmit.com.au" } + ] + }, + { + "name": "iperium", + "categories": [ "org" ], + "cert": "www.imperium.com.au:443", + "domains": [ + { "name": "imperium.com.au" } + ] + }, + { + "name": "Skymesh", + "categories": [ "isp" ], + "cert": "www.skymesh.net.au:443", + "domains": [ + { "name": "skymesh.net.au" } + ] + }, + { + "name": "Solution One", + "categories": [ "org" ], + "cert": "solution-one.com.au:443", + "domains": [ + { "name": "solution-one.com.au" } + ] + }, + { + "name": "Southern Phone", + "categories": [ "org" ], + "cert": "www.southernphone.com.au:443", + "domains": [ + { "name": "southernphone.com.au" } + ] + }, + { + "name": "Spectrum Networks", + "categories": [ "org" ], + "cert": "spectrum.com.au:443", + "domains": [ + { "name": "spectrum.com.au" } + ] + }, + { + "name": "Xenex Systems", + "categories": [ "org" ], + "cert": "xenexsystems.com.au:443", + "domains": [ + { "name": "xenexsystems.com.au" } + ] + }, + { + "name": "XYZ Telecom", + "categories": [ "org" ], + "cert": "www.xyztelecom.com.au:443", + "domains": [ + { "name": "xyztelecom.com.au" } + ] + }, + { + "name": "Yarra City Council", + "categories": [ "org" ], + "cert": "www.yarracity.vic.gov.au:443", + "domains": [ + { "name": "yarracity.vic.gov.au" } + ] + }, + { + "name": "YourDC", + "categories": [ "org" ], + "cert": "yourdc.com.au:443", + "domains": [ + { "name": "yourdc.com.au" } + ] + }, + { + "name": "yurika", + "categories": [ "org" ], + "cert": "www.yurika.com.au:443", + "domains": [ + { "name": "yurika.com.au" } + ] + }, + { + "name": "Web in a Box", + "categories": [ "org" ], + "cert": "www.webinabox.net.au:443", + "domains": [ + { "name": "webinabox.net.au" } + ] + }, + { + "name": "Connected Australia", + "categories": [ "org" ], + "cert": "www.connectedoz.com.au:443", + "domains": [ + { "name": "connectedoz.com.au" } + ] + }, + { + "name": "connect.com.au", + "categories": [ "org" ], + "domains": [ + { "name": "connect.com.au" }, + { "name": "mel.connect.com.au" } + ] + }, + { + "name": "syd4gps0.syd.ops.aspac.uu.net", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "syd4gps0.syd.ops.aspac.uu.net:123" } + ] + }, + { + "name": "vk6hgr.echidna.id.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "vk6hgr.echidna.id.au:123" } + ] + }, + { + "name": "gw.vk6hgr.echidna.id.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "gw.vk6hgr.echidna.id.au:123" } + ] + }, + { + "name": "ntp.2000cn.com.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "ntp.2000cn.com.au:123" } + ] + }, + { + "name": "ntp.mazzanet.net.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "ntp.mazzanet.net.au:123" } + ] + }, + { + "name": "ns1.git.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "ns1.git.au:123" } + ] + }, + { + "name": "ntp.polyfoam.com.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "ntp.polyfoam.com.au:123" } + ] + }, + { + "name": "smtp.juneks.com.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "smtp.juneks.com.au:123" } + ] + }, + { + "name": "time.9r.com.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "time.9r.com.au:123" } + ] + }, + { + "name": "time.esec.com.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "time.esec.com.au:123" } + ] + }, + { + "name": "mel.clearnet.pw", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "mel.clearnet.pw:123" } + ] + }, + { + "name": "ntp1.ds.network", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "ntp1.ds.network:123" } + ] + }, + { + "name": "melbourne.kitten.im", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "melbourne.kitten.im:123" } + ] + }, + { + "name": "pauseq4vntp1.datamossa.io", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "pauseq4vntp1.datamossa.io:123" } + ] + }, + { + "name": "time.tfmcloud.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "time.tfmcloud.au:123" } + ] + }, + { + "name": "svc4.eshorizon.net", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "svc4.eshorizon.net:123" } + ] + }, + { + "name": "syd.clearnet.pw", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "syd.clearnet.pw:123" } + ] + }, + { + "name": "mansfield.id.au", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "mansfield.id.au:123" } + ] + }, + { + "name": "ap-southeast-2.clearnet.pw", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "ap-southeast-2.clearnet.pw:123" } + ] + }, + { + "name": "ntp-sydney.gombadi.com", + "categories": [ "other" ], + "domains": [], + "endpoints": [ + { "host": "ntp-sydney.gombadi.com:123" } + ] + } +] diff --git a/generate.py b/generate.py new file mode 100644 index 0000000..4a72313 --- /dev/null +++ b/generate.py @@ -0,0 +1,15 @@ +from src.NtpDiscovery import NtpDiscovery, NtpLookupCollection +import random +from datetime import datetime, timezone + +coll = NtpLookupCollection.fromfile("data/lookups.json") +coll._data = random.sample(coll._data, 1) +coll.validate() +disc = NtpDiscovery(coll) +report = disc.run() + +with open("README.md", "w") as readme: + readme.write(open("README-header.md", "r").read()) + readme.write("\n") + readme.write(report.get_markdown()) + readme.write("Data last updated {}\n".format(datetime.now(timezone.utc))) diff --git a/scripts/generate.py b/scripts/generate.py deleted file mode 100644 index 4f08f33..0000000 --- a/scripts/generate.py +++ /dev/null @@ -1,114 +0,0 @@ -import json -import glob -import subprocess - -def resolvedns(endpoint): - return subprocess.run( - ["nslookup", "-querytype=A", "-retry=0", "-timeout=3", endpoint], - capture_output=True, - text=True).returncode == 0 - -def ntpdig(endpoint): - print("ntpdigging " + endpoint) - result = subprocess.run( - ["ntpdig", "-j", "-t 3", endpoint], - capture_output=True, - text=True, - timeout=3) - print(result.stdout) - return json.loads(result.stdout) - - -results = [] - -for file in glob.glob("src/*.json"): - with open(file) as f: data = json.load(f) - listresult = { "name": data["name"], "description": data["description"], "servers": [] } - - for server in data["servers"]: - srvresult = { "name": server["name"], "endpoints": [] } - - for endpoint in server["endpoints"]: - eptresult = { "endpoint": endpoint, "dns": False, "ntp": None } - - if resolvedns(endpoint): - eptresult["dns"] = True - - try: - dig = ntpdig(endpoint) - print(dig) - eptresult["ntp"] = { - "stratum": dig["stratum"], - "ip": dig["ip"] - } - except subprocess.TimeoutExpired: - print("ntpdig timed out for " + endpoint) - except json.JSONDecodeError: - print("failed to parse json for " + endpoint) - - srvresult["endpoints"].append(eptresult) - listresult["servers"].append(srvresult) - results.append(listresult) - - - - - - -with open("README.md", "w") as readme: - readme.write(open("README-header.md", "r").read()) - - # sort by list name - results.sort(key=lambda l: l["name"]) - - readme.write("## Table of Contents\n") - for list in results: - readme.write("- [" + list["name"] + "](#" + list["name"] + ")\n") - - for list in results: - readme.write("## " + list["name"] + "\n") - readme.write(list["description"] + "\n") - - # sort by server name - list["servers"].sort(key=lambda s: s["name"]) - - for srv in list["servers"]: - readme.write("### " + srv["name"] + "\n") - readme.write("| Endpoint | A/AAAA | IP | Stratum |\n") - readme.write("| :--------------------------------- | -----: | :--------------- | ------: |\n") - - # sort by endpoint - srv["endpoints"].sort(key=lambda e: e["endpoint"]) - - for ept in srv["endpoints"]: - readme.write("|" + ept["endpoint"]) - readme.write("|" + ("Y" if ept["dns"] else "N")) - if ept["ntp"] is not None: - readme.write("|" + ept["ntp"]["ip"]) - readme.write("|" + str(ept["ntp"]["stratum"])) - else: - readme.write("|||") - readme.write("\n") - - readme.write("\n") - readme.write("\n") - - #print("List name: " + list["name"]) - #print("List description: " + list["description"]) - #print("") - #for srv in list["servers"]: - # print("\tServer name: " + srv["name"]) - # for ept in srv["endpoints"]: - # print("\t\t" + ept["endpoint"]) - # print("\t\t\tResolved?: " + "Yes" if ept["dns"] else "No") - # if ept["ntp"] is not None: - # print("\t\t\tIP: " + ept["ntp"]["ip"]) - # print("\t\t\tStratum: " + str(ept["ntp"]["stratum"])) - # else: - # print("\t\t\tNTP details unavailable") - # print("") - # print("") - #print("") - -print("DONE!") - diff --git a/src/CertificateError.py b/src/CertificateError.py new file mode 100644 index 0000000..9772766 --- /dev/null +++ b/src/CertificateError.py @@ -0,0 +1,5 @@ +from .NtpDiscoveryError import NtpDiscoveryError + +class CertificateError(NtpDiscoveryError): + def __init__(self, message, *args) -> None: + super().__init__(message, args) diff --git a/src/Endpoint.py b/src/Endpoint.py new file mode 100644 index 0000000..15f7681 --- /dev/null +++ b/src/Endpoint.py @@ -0,0 +1,49 @@ + +class Endpoint(object): + def __init__(self, host: str|None = None, port: int|None = None) -> None: + super().__init__() + self._host: str|None = host.strip() if host is not None else None + self._port: int|None = port + + def has_host(self) -> bool: + return self._host is not None + + def get_host(self) -> str|None: + return self._host + + def has_port(self) -> bool: + return self._port is not None + + def get_port(self) -> int|None: + return self._port + + def __hash__(self) -> int: + return hash(str(self)) + + def __eq__(self, other: object) -> bool: + if type(other) == __class__: + return self._host == other._host and self._port == other._port + elif type(other) == str: + return __class__.fromstring(other) == self + elif type(other) == tuple[str, int]: + return __class__(other[0], other[1]) == self + raise ValueError("other object is not comparable") + + def __ne__(self, other: object) -> bool: + return not self.__eq__(other) + + def __str__(self) -> str: + return ("%s%s%s" % ( + self._host if self._host is not None else "", + ":" if self._port is not None else "", + str(self._port) if self._port is not None else "")) + + def totuple(self) -> tuple[str, int]: + return (self._host, self._port) + + @classmethod + def fromstring(cls, s: str, defaultport: int|None = None): + parts = s.strip().split(":", 2) + host = parts[0] if len(parts) > 1 else None + port = int(parts[1]) if len(parts) > 1 else defaultport + return __class__(host, port) diff --git a/src/NtpDetail.py b/src/NtpDetail.py new file mode 100644 index 0000000..9076eca --- /dev/null +++ b/src/NtpDetail.py @@ -0,0 +1,19 @@ +import ntp.packet + +class NtpDetail(object): + + def __init__(self, packet: ntp.packet.SyncPacket) -> None: + super().__init__() + self._packet: ntp.packet.SyncPacket = packet + + def version(self) -> int: + return self._packet.version() + + def ip(self) -> str: + return self._packet.resolved + + def stratum(self) -> int: + return self._packet.stratum + + def leap(self) -> str: + return self._packet.leap() diff --git a/src/NtpDiscovery.py b/src/NtpDiscovery.py new file mode 100644 index 0000000..1110eac --- /dev/null +++ b/src/NtpDiscovery.py @@ -0,0 +1,114 @@ +from .Endpoint import Endpoint +from .NtpLookupCollection import NtpLookupCollection +from .NtpDiscoveryReport import NtpDiscoveryReport +from .NtpX509DiscoveryService import NtpX509DiscoveryService +from .NtpSrvDiscoveryService import NtpSrvDiscoveryService +from .NtpDnsProbeDiscoveryService import NtpDnsProbeDiscoveryService +from .NtpDetail import NtpDetail +from .util import util +import concurrent.futures +import ntp.packet +import dns.inet +import dns.ipv4 +import dns.name + +class NtpDiscovery(object): + + class _GetNtpResult(object): + def __init__(self, name: str, endpoint: Endpoint) -> None: + super().__init__() + self.name: str = name + self.endpoint: Endpoint = endpoint + self.ntps: list[NtpDetail]|None = None + + def __init__(self, lookups: NtpLookupCollection) -> None: + super().__init__() + self._lookups = lookups + + @classmethod + def _get_ntp_thread_func(cls, name: str, endpoint: Endpoint) -> _GetNtpResult: + result: __class__._GetNtpResult = __class__._GetNtpResult(name, endpoint) + print("Trying NTP {}...".format(endpoint)) + # TODO: add timeout param? + packets: list[ntp.packet.SyncPacket] = util.ntpdig(endpoint.get_host(), endpoint.get_port(), 5) + result.ntps = list(map(lambda p: NtpDetail(p), packets)) + return result + + @classmethod + def _do_dns_domain_probe(cls, domain: dns.name.Name, current_endpoints: set[Endpoint]) -> set[Endpoint]: + + converted_names = filter(lambda e: e.has_host(), current_endpoints) + converted_names = filter(lambda e: not dns.inet.is_address(e.get_host()), converted_names) + converted_names = map(lambda e: dns.name.from_unicode(e.get_host()), converted_names) + + # is n a subdomain of var domain? + subdomains = filter(lambda n: n.is_subdomain(domain), converted_names) + new_names = set(map(lambda s: s.derelativize(domain).to_unicode(True), subdomains)) + + print(list(new_names)) + unique_names = NtpDnsProbeDiscoveryService.get_unique_names(new_names) + print(list(unique_names)) + + srv = NtpDnsProbeDiscoveryService(domain) + srv.set_names(unique_names) + + return srv.get_endpoints() + + def run(self) -> NtpDiscoveryReport: + + # For each entry in the lookup collection... + # + # 1. Collect a list of endpoints to query + # 1a. Add predefined endpoints to list + # 1b. Run a DNS SRV discovery on a given domain and add each result + # to the list + # 1c. Run an X509 discovery on each certificate endpoint and add each + # result to the list + # 1d. Run a DNS common name probe on each domain and add each result + # to the list + # + # 2. Perform an NTP query on each endpoint in the list and add the result + # to a new list + # + # 3. Return a report + # + + # { "Google": [ time.google.com:123, etc... ] } + endpoints_to_query: dict[str, set[Endpoint]] = {} + + for lookup in self._lookups: + + lookup_endpoints: set[Endpoint] = set() + + if lookup.has_endpoints(): + lookup_endpoints |= lookup.get_endpoints() + + if lookup.has_cert_endpoint(): + lookup_endpoints |= NtpX509DiscoveryService(lookup.get_cert_endpoint()).get_endpoints() + + if lookup.has_domains(): + for domain in lookup.get_domains(): + lookup_endpoints |= NtpSrvDiscoveryService(domain).get_endpoints() + lookup_endpoints |= __class__._do_dns_domain_probe(domain, lookup_endpoints) + + endpoints_to_query[lookup.get_name()] = lookup_endpoints + + report: NtpDiscoveryReport = NtpDiscoveryReport() + + with concurrent.futures.ThreadPoolExecutor(max_workers=16) as exe: + futures: list[concurrent.futures.Future] = [] + + for name, endpoints in endpoints_to_query.items(): + for endpoint in endpoints: + futures.append(exe.submit(__class__._get_ntp_thread_func, name, endpoint)) + + for future in concurrent.futures.as_completed(futures): + try: + result = future.result() + except ntp.packet.SyncException as err: + print(err) + continue + + report.append_multiple(result.name, result.endpoint, result.ntps) + + return report diff --git a/src/NtpDiscoveryError.py b/src/NtpDiscoveryError.py new file mode 100644 index 0000000..68a8aae --- /dev/null +++ b/src/NtpDiscoveryError.py @@ -0,0 +1,4 @@ + +class NtpDiscoveryError(Exception): + def __init__(self, *args: object) -> None: + super().__init__(*args) diff --git a/src/NtpDiscoveryReport.py b/src/NtpDiscoveryReport.py new file mode 100644 index 0000000..7baea5a --- /dev/null +++ b/src/NtpDiscoveryReport.py @@ -0,0 +1,56 @@ +from .Endpoint import Endpoint +from .NtpDetail import NtpDetail + +class NtpDiscoveryReport(object): + + def __init__(self) -> None: + super().__init__() + self._data: dict[str, dict[Endpoint, list[NtpDetail]]] = {} + + def __iter__(self) -> iter: + return iter(self._data) + + def __len__(self) -> int: + total = 0 + for _, endpoints in self._data.items(): + for _, ntps in endpoints.items(): + total += len(ntps) + return total + + def set_keys(self, name: str, endpoint: Endpoint): + if not name in self._data: + self._data[name] = {} + if not endpoint in self._data[name]: + self._data[name][endpoint] = [] + + def append(self, name: str, endpoint: Endpoint, ntp: NtpDetail): + self.set_keys(name, endpoint) + self._data[name][endpoint].append(ntp) + + def append_multiple(self, name: str, endpoint: Endpoint, ntps: list[NtpDetail]): + self.set_keys(name, endpoint) + for ntp in ntps: + self.append(name, endpoint, ntp) + + def generate_markdown(self): + for name, endpoint_dict in sorted(self._data.items()): + for endpoint, ntps in sorted(endpoint_dict.items(), key=lambda item: str(item[0])): + yield { + "name": name, + "endpoint": endpoint, + "ntps": ntps + } + + def get_markdown(self) -> str: + buff: str = "" + for name, endpoint_dict in sorted(self._data.items()): + buff += "### {}\n\n".format(name) + buff += "| endpoint | ip address | version | stratum | leap |\n" + buff += "| -------- | ---------- | ------- | ------- | ---- |\n" + for endpoint, ntps in sorted(endpoint_dict.items(), key=lambda item: str(item[0])): + buff += "|`{}`|||||\n".format(endpoint) + #buff += ("||||" if len(ntps) > 0 else "n/a|n/a|n/a|n/a|") + "\n" + for ntp in ntps: + buff += "||{}|{:d}|s{:d}|{}|\n".format(ntp.ip(), ntp.version(), ntp.stratum(), ntp.leap()) + buff += "\n" + return buff diff --git a/src/NtpDiscoveryService.py b/src/NtpDiscoveryService.py new file mode 100644 index 0000000..f6ef8a5 --- /dev/null +++ b/src/NtpDiscoveryService.py @@ -0,0 +1,9 @@ +from .Endpoint import Endpoint + +class NtpDiscoveryService(object): + + def __init__(self) -> None: + super().__init__() + + def get_endpoints(self) -> set[Endpoint]: + pass diff --git a/src/NtpDnsProbeDiscoveryService.py b/src/NtpDnsProbeDiscoveryService.py new file mode 100644 index 0000000..5add8e7 --- /dev/null +++ b/src/NtpDnsProbeDiscoveryService.py @@ -0,0 +1,89 @@ +from .NtpDiscoveryService import NtpDiscoveryService +from .Endpoint import Endpoint +import concurrent.futures +import dns.name +import dns.resolver +import dns.exception + +class NtpDnsProbeDiscoveryService(NtpDiscoveryService): + + DEFAULT_NTP_PORT: int = 123 + DEFAULT_TIMEOUT: float = 5 + DEFAULT_THREAD_COUNT: int = 8 + + DEFAULT_NAMES: set[str] = set([ + "ntp", + "ntp0", + "ntp1", + "ntp2", + "ntp3", + "ntp4", + "time", + "time0", + "time1", + "time2", + "time3", + "time4", + "clock", + "ns", + "ns0", + "ns1", + "ns2", + "ns3", + "ns4", + "tick", + "tock", + "tic", + "toc", + "chime", + "chronos" + ]) + + def __init__( + self, + domain: dns.name.Name, + timeout: float|None = DEFAULT_TIMEOUT, + threads: int = DEFAULT_THREAD_COUNT, + names: set[str] = DEFAULT_NAMES) -> None: + super().__init__() + self._domain: dns.name.Name = domain + self._timeout: float|None = timeout + self._threads: int = threads + self._names: set[str] = names + + @classmethod + def _get_host_thread(cls, q: dns.name.Name, timeout: float|None) -> Endpoint: + print("Trying host {0}...".format(q.to_unicode())) + resp = dns.resolver.resolve(q, lifetime=timeout) + return Endpoint(str(resp.qname).rstrip(".*"), cls.DEFAULT_NTP_PORT) + + @classmethod + def get_unique_names(cls, names: set[str]) -> set[str]: + return cls.DEFAULT_NAMES.difference(names) + + def set_names(self, names: set[str]) -> None: + self._names = names + + def get_endpoints(self) -> set[Endpoint]: + + endpoints: set[Endpoint] = set() + print("Querying names {}...".format(self._names)) + + with concurrent.futures.ThreadPoolExecutor(max_workers=self._threads) as exe: + + futures: list[concurrent.futures.Future] = [] + + for name in map(lambda n: dns.name.from_unicode(n, self._domain), self._names): + futures.append(exe.submit(self._get_host_thread, name, self._timeout)) + + for future in concurrent.futures.as_completed(futures): + try: + endpoints.add(future.result()) + except (dns.resolver.NXDOMAIN, + dns.resolver.NoNameservers, + dns.resolver.NoAnswer, + dns.exception.Timeout) as err: + print(err) + pass + + return endpoints diff --git a/src/NtpLookup.py b/src/NtpLookup.py new file mode 100644 index 0000000..ec05ed3 --- /dev/null +++ b/src/NtpLookup.py @@ -0,0 +1,44 @@ +import dns.name +from .Endpoint import Endpoint + +class NtpLookup(object): + + DEFAULT_HTTPS_PORT: int = 443 + DEFAULT_NTP_PORT: int = 123 + + def __init__(self, data: dict) -> None: + super().__init__() + self._data: dict = data + + def __str__(self) -> str: + return self.get_name() if self.has_name() else None + + def has_name(self) -> bool: + return "name" in self._data and type(self._data["name"]) == str + + def get_name(self) -> str: + return self._data["name"] + + def has_categories(self) -> bool: + return "categories" in self._data and type(self._data["categories"]) == list + + def get_categories(self) -> set[str]: + return set(map(lambda c: c.strip().lower().lstrip("#"), self._data["categories"])) + + def has_cert_endpoint(self) -> bool: + return "cert" in self._data and type(self._data["cert"]) == str + + def get_cert_endpoint(self) -> Endpoint|None: + return Endpoint.fromstring(self._data["cert"], defaultport=__class__.DEFAULT_HTTPS_PORT) + + def has_domains(self) -> bool: + return "domains" in self._data and type(self._data["domains"]) == list + + def get_domains(self) -> set[dns.name.Name]: + return set(map(lambda d: dns.name.from_unicode(d["name"]), self._data["domains"])) + + def has_endpoints(self) -> bool: + return "endpoints" in self._data and type(self._data["endpoints"]) == list + + def get_endpoints(self) -> set[Endpoint]: + return set(map(lambda e: Endpoint.fromstring(e["host"], defaultport=__class__.DEFAULT_NTP_PORT), self._data["endpoints"])) diff --git a/src/NtpLookupCollection.py b/src/NtpLookupCollection.py new file mode 100644 index 0000000..59c124b --- /dev/null +++ b/src/NtpLookupCollection.py @@ -0,0 +1,72 @@ +import json +from .NtpLookup import NtpLookup + +class NtpLookupCollection(object): + + def __init__(self) -> None: + super().__init__() + self._data = None + + def validate(self): + names: set[str] = set() + for lookup in self._data: + + if not lookup.has_name(): + raise ValueError("A lookup within {} does not have a name".format(__class__.__name__)) + + if lookup.get_name().startswith("#"): + raise ValueError("{} may not begin with a # in {}".format(lookup.get_name(), __class__.__name__)) + + if lookup.get_name() in names: + raise ValueError("{} is duplicated in {}".format(lookup.get_name(), __class__.__name__)) + + names.add(lookup.get_name()) + return True + + def get_by_name(self, name: str) -> NtpLookup: + for lookup in self._data: + if name == lookup.get_name(): + return lookup + return None + + def get_by_category(self, category: str) -> set[NtpLookup]: + results: set[NtpLookup] = set() + category = category.lower().strip().lstrip("#") + for lookup in self._data: + if lookup.has_categories() and category in lookup.get_categories(): + results.add(lookup) + return results + + def get_categories(self) -> set[str]: + cats = set() + for l in self._data: + cats |= l.get_categories() + return cats + + def __bool__(self) -> bool: + return self._data is not None + + def __len__(self) -> int: + return len(self._data) + + def __iter__(self): + return iter(self._data) + + def __getitem__(self, index: int|str) -> NtpLookup|None: + if type(index) == int: + return self._data[index] + elif type(index) == str: + if index.startswith("#"): + return self.get_by_category(index) + else: + return self.get_by_name(index) + raise TypeError("index type is invalid for {}".format(__class__.__name__)) + + @classmethod + def fromfile(cls, filepath: str): + lc = cls() + with open(filepath) as f: + data = json.load(f) + lc._data = list(map(lambda e: NtpLookup(e), data)) + lc._data.sort(key=lambda l: l.get_name()) + return lc diff --git a/src/NtpSrvDiscoveryService.py b/src/NtpSrvDiscoveryService.py new file mode 100644 index 0000000..dd61b91 --- /dev/null +++ b/src/NtpSrvDiscoveryService.py @@ -0,0 +1,68 @@ +from .Endpoint import Endpoint +from .NtpDiscoveryService import NtpDiscoveryService +import dns +import dns.exception +import dns.name +import dns.rdtypes.IN.SRV +import dns.resolver + +class NtpSrvDiscoveryService(NtpDiscoveryService): + + SRV_SERVICE_NAME: str = "ntp" + SRV_PROTO_NAME: str = "udp" + DEFAULT_NTP_PORT: int = 123 + DEFAULT_TIMEOUT: float = 5 + DEFAULT_ENDPOINT_LIMIT: int|None = None + + def __init__( + self, + domain: dns.name.Name, + timeout: float|None = DEFAULT_TIMEOUT, + endpoint_limit: int|None = DEFAULT_ENDPOINT_LIMIT, + subdomains_only: bool = True) -> None: + super().__init__() + self._domain: dns.name.Name = domain + self._timeout: float|None = timeout + self._endpoint_limit: int|None = endpoint_limit + self._subdomains_only = subdomains_only + + def set_endpoint_limit(self, limit: int|None): + self._endpoint_limit = limit + + @classmethod + def get_records(cls, domain: dns.name.Name, timeout: float|None) -> list[dns.rdtypes.IN.SRV.SRV]: + qname = dns.name.from_text("_{}._{}".format(cls.SRV_SERVICE_NAME, cls.SRV_PROTO_NAME), domain) + result = dns.resolver.resolve(qname, dns.rdatatype.SRV, lifetime=timeout) + return list(result.rrset) + + def get_endpoints(self) -> set[Endpoint]: + + records: set[Endpoint] = set() + + try: + records = self.get_records(self._domain, self._timeout) + except (dns.resolver.NXDOMAIN, + dns.resolver.NoNameservers, + dns.resolver.NoAnswer, + dns.exception.Timeout) as err: + print("DNS SRV failed for {}".format(self._domain)) + print(err) + return set() + + print("SRV DNS response for {} is {}".format( + self._domain.to_unicode(), list(map(lambda r: r.target.to_unicode(), records)))) + + if self._subdomains_only: + records = filter(lambda r: r.target.is_subdomain(self._domain), records) + + # create endpoints + endpoints = map(lambda r: Endpoint(r.target.to_unicode(True), r.port), records) + + # unique + endpoints = set(endpoints) + + # limit + if self._endpoint_limit is not None: + endpoints = set(list(endpoints)[:self._endpoint_limit]) + + return endpoints diff --git a/src/NtpX509DiscoveryService.py b/src/NtpX509DiscoveryService.py new file mode 100644 index 0000000..1ffd9cf --- /dev/null +++ b/src/NtpX509DiscoveryService.py @@ -0,0 +1,123 @@ +import dns.inet +import dns.name +from .NtpDiscoveryService import NtpDiscoveryService +from .Endpoint import Endpoint +from OpenSSL import SSL, crypto +import re +import socket +import dns + +class NtpX509DiscoveryService(NtpDiscoveryService): + + DEFAULT_NTP_PORT: int = 123 + DEFAULT_TIMEOUT: int = 5 + DEFAULT_ENDPOINT_LIMIT: int|None = None + + def __init__( + self, + endpoint: Endpoint, + timeout: int|None = DEFAULT_TIMEOUT, + endpoint_limit: int|None = DEFAULT_ENDPOINT_LIMIT, + subdomains_only: bool = True) -> None: + super().__init__() + self._endpoint: Endpoint = endpoint + self._timeout: int|None = timeout + self._endpoint_limit: int|None = endpoint_limit + self._subdomains_only: bool = subdomains_only + + def set_endpoint_limit(self, limit: int|None): + self._endpoint_limit = limit + + @classmethod + def get_certificate(cls, endpoint: Endpoint, hostname: str, timeout: int|None = 5) -> crypto.X509: + + if endpoint.get_host() == None: + raise ValueError("Endpoint has no host", str(endpoint), hostname) + + if hostname == None or hostname.isspace(): + raise ValueError("Hostname is not set", str(endpoint), hostname) + + ctx = SSL.Context(SSL.TLS_CLIENT_METHOD) + ctx.set_min_proto_version(SSL.SSL3_VERSION) + ctx.set_max_proto_version(SSL.TLS1_3_VERSION) + + if timeout is not None: + ctx.set_timeout(timeout) + + con = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + con.set_tlsext_host_name(bytes(hostname, "utf-8")) + + try: + con.connect(endpoint.totuple()) + con.do_handshake() + return con.get_peer_certificate() + except (socket.gaierror, SSL.Error) as err: + print("==========================") + print("Socket or SSL/TLS Error") + print(err) + print("Endpoint: {}".format(endpoint)) + print("Hostname: {}".format(hostname)) + print("Re-raising error...") + print("==========================") + # rethrow so we can handle connection shutdown + raise err + finally: + try: con.shutdown() + except: pass + + @classmethod + def get_subject_alt_names(cls, cert: crypto.X509) -> set[str]|None: + # eg. IP Address:127.0.0.1, IP Address:192.168.1.1, DNS:host.internal, DNS:host2.internal, DNS:ntp.internal + for i in range(cert.get_extension_count()): + ext = cert.get_extension(i) + if ext.get_short_name().decode().strip().lower() == "subjectaltname": + names = str(ext).strip() + return set(re.findall(r"(?:(?:IP Address)|(?:DNS)):([^,$]+)", names, re.IGNORECASE)) + return None + + def get_endpoints(self) -> set[Endpoint]: + + try: + cert = self.get_certificate(self._endpoint, self._endpoint.get_host(), self._timeout) + except (socket.gaierror, SSL.Error) as err: + print("Failed to obtain X509 certificate for {}".format(self._endpoint)) + print(err) + return set() + + hosts = self.get_subject_alt_names(cert) + + if hosts is None: + return set() + + print("X509 certificate hosts from {} are {}...".format(self._endpoint, hosts)) + + # some filtering + hosts = filter(lambda h: h is not None, hosts) + hosts = map(lambda h: h.strip() , hosts) + hosts = filter(lambda h: not h.isspace(), hosts) + + # remove wildcard domains + hosts = filter(lambda h: not h.startswith("*."), hosts) + + # unique + hosts = set(hosts) + + # create the endpoints + endpoints = map(lambda d: Endpoint(d, __class__.DEFAULT_NTP_PORT), hosts) + + if self._endpoint_limit is not None: + endpoints = set(list(endpoints)[:self._endpoint_limit]) + + if self._subdomains_only: + the_domain = dns.name.from_unicode(self._endpoint.get_host()) + # some endpoints may be ip addresses + names = filter(lambda e: not dns.inet.is_address(e.get_host()), endpoints) + names_and_endpoints = map(lambda e: (dns.name.from_unicode(e.get_host()), e), names) + names_and_endpoints = filter(lambda ne: ne[0].is_subdomain(the_domain), names_and_endpoints) + endpoints = map(lambda ne: ne[1], names_and_endpoints) + endpoints = set(endpoints) + + print("X509 certificate hosts for {} converted to endpoints are {}".format( + self._endpoint, list(map(lambda e: str(e), endpoints)))) + + return endpoints diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/isps.json b/src/isps.json deleted file mode 100644 index 0b60180..0000000 --- a/src/isps.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "name": "ISPs", - "description": "Internet Service Providers", - "servers": [ - { - "name": "Spintel", - "endpoints": [ - "203.23.237.200" - ] - }, - { - "name": "Aussie Broadband", - "endpoints": [ - "ntp-bne.aussiebroadband.com.au", - "ntp-syd.aussiebroadband.com.au", - "ntp-mel.aussiebroadband.com.au", - "ntp-adl.aussiebroadband.com.au", - "ntp-per.aussiebroadband.com.au" - ] - }, - { - "name": "Exetel", - "endpoints": [ - "clock.exetel.com.au" - ] - }, - { - "name": "Telstra", - "endpoints": [ - "chronos.ntp.telstra.net", - "chronos1.ntp.telstra.net", - "tic.ntp.telstra.net", - "toc.ntp.telstra.net" - ] - }, - { - "name": "TPG", - "endpoints": [ - "ntp1.tpg.com.au", - "ntp2.tpg.com.au" - ] - }, - { - "name": "Optus", - "endpoints": [ - "time.optusnet.com.au", - "time01.mel.optus.net", - "time02.mel.optus.net" - ] - }, - { - "name": "iiNet", - "endpoints": [ - "time.iinet.net.au", - "ntp.iinet.net.au", - "ntp.ii.net", - "ntp1.iinet.net.au", - "ntp2.iinet.net.au" - ] - }, - { - "name": "Internode", - "endpoints": [ - "ntp.on.net", - "ns2.on.net", - "ntp.internode.on.net" - ] - }, - { - "name": "iPrimus", - "endpoints": [ - "ntp.iprimus.com.au" - ] - }, - { - "name": "Vocus", - "endpoints": [ - "ntp.vocus.network", - "ntp01.vic.vocus.network", - "ntp02.vic.vocus.network" - ] - } - ] -} diff --git a/src/ntpdig.py b/src/ntpdig.py new file mode 100644 index 0000000..77f0fc2 --- /dev/null +++ b/src/ntpdig.py @@ -0,0 +1,497 @@ +#! @PYSHEBANG@ +# -*- coding: utf-8 -*- +""" +ntpdig - simple SNTP client + +""" + +# Copyright the NTPsec project contributors +# +# SPDX-License-Identifier: BSD-2-Clause +# This code runs identically under Python 2 and Python 3. Keep it that way! + +from __future__ import print_function, division +import getopt +import math +import select +import socket +import sys +import time + +try: + import ntp.magic + import ntp.packet + import ntp.util +except ImportError as e: + sys.stderr.write( + "ntpdig: can't find Python NTP library -- check PYTHONPATH.\n") + sys.stderr.write("%s\n" % e) + sys.exit(1) +# This code is somewhat stripped down from the legacy C version. It +# does however have one additional major feature; it can filter +# out falsetickers from multiple samples, like the ntpdate of old, +# rather than just taking the first reply it gets. +# +# Listening to broadcast addresses is not implemented because that is +# impossible to secure. KOD recording is also not implemented, as it +# can too easily be spammed. Thus, the options -b and -K are not +# implemented. +# +# There are no version 3 NTP servers left, so the -o version for setting +# NTP version has been omitted. +# +# Because ntpdig doesn't use symmetric-peer mode (it never did, and NTPsec has +# abolished that mode because it was a security hazard), there's no need to +# set the packet source port, so -r/--usereservedport has been dropped. +# If this option ever needs to be reinstated, the magic is described here: +# http://stackoverflow.com/questions/2694212/socket-set-source-port-number +# and would be s.bind(('', 123)) right after the socket creation. +# +# The -w/--wait and -W/--nowait options only made sense with asynchronous +# DNS. Asynchronous DNS was absurd overkill for this application, we are +# not looking up 20,000 hosts here. It has not been implemented, so neither +# have these options. +# +# Finally, logging to syslog by default was a design error, violating +# Unix principles, that has been fixed. To get this behavior when +# running in a script, redirect standard error to logger(1). +# +# The one new option in this version is -p, borrowed from ntpdate. + + +def read_append(s, packets, packet, sockaddr, server): + d, a = s.recvfrom(1024) + #if debug >= 2: + # ntp.packet.dump_hex_printable(d) + #if credentials: + #if not ntp.packet.Authenticator.have_mac(d): + #if debug: + # log("no MAC on reply from %s" % packet.hostname) + # if not credentials.verify_mac(d, packet_end=48, mac_begin=48): + # packet.trusted = False + # log("MAC verification on reply from %s failed" + # % sockaddr[0]) + # elif debug: + # log("MAC verification on reply from %s succeeded" + # % sockaddr[0]) + pkt = ntp.packet.SyncPacket(d) + pkt.hostname = server + pkt.resolved = sockaddr[0] + packets.append(pkt) + return packets + + +def queryhost(server, concurrent, timeout=5, port=123, bindaddr=None): + "Query IP addresses associated with a specified host." + try: + iptuples = socket.getaddrinfo(server, port, + 0, socket.SOCK_DGRAM, + socket.IPPROTO_UDP) + except socket.gaierror as e: + #log("lookup of %s failed, errno %d = %s" % (server, e.args[0], e.args[1])) + return [] + if bindaddr: + try: + bindsock = socket.getaddrinfo(bindaddr,None,af, + socket.SOCK_DGRAM,socket.IPPROTO_UDP) + except socket.gaierror as e: + #log("lookup of %s failed, errno %d = %s" % (server, e.args[0], e.args[1])) + raise SystemExit(1) + sockets = [] + packets = [] + request = ntp.packet.SyncPacket() + request.transmit_timestamp = ntp.packet.SyncPacket.posix_to_ntp( + time.time()) + packet = request.flatten() + #needgap = (len(iptuples) > 1) and (gap > 0) + needgap = False + firstloop = True + debug = False + for (family, socktype, proto, canonname, sockaddr) in iptuples: + if needgap and not firstloop: + time.sleep(gap) + if firstloop: + firstloop = False + if debug: + log("querying %s (%s)" % (sockaddr[0], server)) + try: + s = socket.socket(family, socktype) + except OSError: + #if debug: + # log("Skipping because socket for %s of family" + # " %d, type %d could not be formed." % + # (sockaddr[0], family, socktype)) + continue + if bindaddr: + try: + #if debug: + # log("Binding to Source IP %s," % bindaddr) + s.bind(bindsock[0][4]) + except OSError as e: + log("binding to %s failed, errno %d = %s" % (bindaddr, e.args[0], e.args[1])) + raise SystemExit(1) + #if keyid and keytype and passwd: + # if debug: + # log("authenticating with %s key %d" % (keytype, keyid)) + # mac = ntp.packet.Authenticator.compute_mac(packet, + # keyid, keytype, passwd) + # if mac is None: + # log("MAC generation failed while querying %s" % server) + # raise SystemExit(1) + # else: + # packet += mac + try: + s.sendto(packet, sockaddr) + except socket.error as e: + #if debug: + # log("socket error on transmission: %s" % e) + continue + #if debug >= 2: + # log("Sent to %s:" % (sockaddr[0],)) + # ntp.packet.dump_hex_printable(packet) + if concurrent: + sockets.append(s) + else: + r, _, _ = select.select([s], [], [], timeout) + if r: + read_append(s, packets, packet, sockaddr, server) + while sockets: + r, _, _ = select.select(sockets, [], [], timeout) + if not r: + return packets + for s in sockets: + read_append(s, packets, packet, sockaddr, server) + sockets.remove(s) + return packets + + +def clock_select(packets): + "Select the pick-of-the-litter clock from the samples we've got." + # This is a slightly simplified version of the filter ntpdate used + NTP_INFIN = 15 # max stratum, infinity a la Bellman-Ford + + # This first chunk of code is supposed to go through all + # servers we know about to find the servers that + # are most likely to succeed. We run through the list + # doing the sanity checks and trying to insert anyone who + # looks okay. We are at all times aware that we should + # only keep samples from the top two strata. + # + filtered = [] + for response in packets: + def drop(msg): + log("%s: Response dropped: %s" % (response.hostname, msg)) + if response.stratum > NTP_INFIN: + drop("stratum too high") + continue + if response.version() < ntp.magic.NTP_OLDVERSION: + drop("response version %d is too old" % response.version()) + continue + if response.mode() != ntp.magic.MODE_SERVER: + drop("unexpected response mode %d" % response.mode()) + continue + if response.version() > ntp.magic.NTP_VERSION: + drop("response version %d is too new" % response.version()) + continue + if response.stratum == 0: + # FIXME: Do some kind of semi-useful diagnostic dump here + drop("stratum 0, probable KOD packet") + continue + if response.leap() == "unsync": + drop("leap not in sync") + continue + if not response.trusted: + drop("request was authenticated but server is untrusted") + continue + # Bypass this test if we ever support broadcast-client mode again + if response.origin_timestamp == 0: + drop("unexpected response timestamp") + continue + filtered.append(response) + + if len(filtered) <= 1: + return filtered + + # Sort by stratum and other figures of merit + filtered.sort(key=lambda s: (s.stratum, s.synchd(), s.root_delay)) + + # Return the best + return filtered[:1] + + +def report(packet, json): + "Report on the SNTP packet selected for display, and its adjustment." + say = sys.stdout.write + + packet.posixize() + + # The server's idea of the time + t = time.localtime(int(packet.transmit_timestamp)) + ms = int(packet.transmit_timestamp * 1000000) % 1000000 + + if t.tm_isdst: + tmoffset = -time.altzone // 60 # In minutes + else: + tmoffset = -time.timezone // 60 # In minutes + + # Number of decimal digits of precision indicated by the precision field + digits = min(6, -int(math.log10(2**packet.precision))) + + date = time.strftime("%Y-%m-%d", t) + tod = time.strftime("%T", t) + (".%0*d" % (digits, ms)).rstrip() + sgn = ("%+d" % tmoffset)[0] + tz = "%s%02d%02d" % (sgn, abs(tmoffset) // 60, tmoffset % 60) + + if json: + say('{"time":"%sT%s%s","offset":%f,"precision":%f,"host":"%s",' + '"ip":"%s","stratum":%s,"leap":"%s","adjusted":%s,"delay":%f}\n' + % (date, tod, tz, + packet.adjust(), packet.synchd(), + packet.hostname, packet.resolved or packet.hostname, + packet.stratum, packet.leap(), + "true" if adjusted else "false", packet.delta())) + else: + say("%s %s (%s) %+f +/- %f %s" + % (date, tod, tz, + packet.adjust(), packet.synchd(), + packet.hostname)) + if packet.resolved and packet.resolved != packet.hostname: + say(" " + packet.resolved) + say(" s%d %s\n" % (packet.stratum, packet.leap())) + + +usage = """ +USAGE: ntpdig [- [] | --[{=| }]]... + [ hostname-or-IP ...] + Flg Arg Option-Name Description + -4 no ipv4 Force IPv4 DNS name resolution + - prohibits the option 'ipv6' + -6 no ipv6 Force IPv6 DNS name resolution + - prohibits the option 'ipv4' + -a Num authentication Enable authentication with the numbered key + -c yes concurrent Hosts to be queried concurrently + -d no debug Increase debug verbosity + -D yes set-debug-level Set debug verbosity + -g yes gap Set gap between requests in milliseconds + -I IP bindaddr Set the source address to send request on + -j no json Use JSON output format + -l Str logfile Log to specified logfile + - prohibits the option 'syslog' + -p yes samples Number of samples to take (default 1) + -S no step Set (step) the time with clock_settime() + - prohibits the option 'step' + -s no slew Set (slew) the time with adjtime() + - prohibits the option 'slew' + -t Num timeout Request timeout in seconds (default 5) + -k Str keyfile Specify a keyfile. ntpdig will look in this file + for the key specified with -a + -V no version Output version information and exit + -h no help Display extended usage information and exit +""" + + +if __name__ == '__main__': + bin_ver = "ntpsec-@NTPSEC_VERSION_EXTENDED@" + ntp.util.stdversioncheck(bin_ver) + try: + try: + (options, arguments) = getopt.getopt( + sys.argv[1:], + "46a:c:dD:g:hI:jk:l:M:o:p:r:Sst:wWV", + ["ipv4", "ipv6", + "bindaddr=", + "authentication=", + "concurrent=", + "gap=", "help", "json", + "keyfile=", "logfile=", + "replay=", + "samples=", "steplimit=", + "step", "slew", + "timeout=", + "debug", "set-debug-level=", + "version"]) + except getopt.GetoptError as e: + print(e) + raise SystemExit(1) + progname = sys.argv[0] + + logfp = sys.stderr + log = lambda m: logfp.write("ntpdig: %s\n" % m) + + af = socket.AF_UNSPEC + bindaddr = None + authkey = None + concurrent_hosts = [] + debug = 0 + gap = .05 + json = False + keyfile = None + steplimit = 0 # Default is intentionally zero + samples = 1 + step = False + slew = False + timeout = 5 + replay = None + try: + for (switch, val) in options: + if switch in ("-4", "--ipv4"): + af = socket.AF_INET + elif switch in ("-6", "--ipv6"): + af = socket.AF_INET6 + elif switch in ("-a", "--authentication"): + errmsg = "Error: -a parameter '%s' not a number\n" + authkey = ntp.util.safeargcast(val, int, errmsg, usage) + elif switch in ("-c", "--concurrent"): + concurrent_hosts.append(val) + elif switch in ("-d", "--debug"): + debug += 1 + elif switch in ("-D", "--set-debug-level"): + errmsg = "Error: -D parameter '%s' not a number\n" + debug = ntp.util.safeargcast(val, int, errmsg, usage) + elif switch in ("-g", "--gap"): + errmsg = "Error: -g parameter '%s' not a number\n" + gap = ntp.util.safeargcast(val, int, errmsg, usage) + elif switch in ("-I", "--bindaddr"): + bindaddr = val + elif switch in ("-j", "--json"): + json = True + elif switch in ("-k", "--keyfile"): + keyfile = val + elif switch in ("-l", "--logfile"): + try: + logfp = open(val, "w") + except OSError: + sys.stderr.write("logfile open of %s failed.\n" % val) + raise SystemExit(1) + elif switch in ("-M", "--steplimit"): + errmsg = "Error: -M parameter '%s' not a number\n" + steplimit = ntp.util.safeargcast(val, int, errmsg, usage) + steplimit /= 1000.0 + elif switch in ("-p", "--samples"): + errmsg = "Error: -p parameter '%s' not a number\n" + samples = ntp.util.safeargcast(val, int, errmsg, usage) + if samples < 1: # If <1 it won't run at all + samples = 1 + elif switch in ('-r', "--replay"): + replay = val + elif switch in ("-S", "--step"): + step = True + elif switch in ("-s", "--slew"): + slew = True + elif switch in ("-t", "--timeout"): + errmsg = "Error: -t parameter '%s' not a number\n" + timeout = ntp.util.safeargcast(val, int, errmsg, usage) + elif switch in ("-h", "--help"): + print(usage) + raise SystemExit(0) + elif switch in ("-V", "--version"): + print("ntpdig %s" % bin_ver) + raise SystemExit(0) + else: + sys.stderr.write( + "Unknown command line switch or missing argument.\n") + sys.stderr.write(usage) + raise SystemExit(1) + except ValueError: + sys.stderr.write("Invalid argument.\n") + sys.stderr.write(usage) + raise SystemExit(1) + + gap /= 1000 # convert to milliseconds + + credentials = keyid = keytype = passwd = None + try: + credentials = ntp.packet.Authenticator(keyfile) + except (OSError, IOError): + sys.stderr.write("ntpdig: %s nonexistent or unreadable\n" % + keyfile) + raise SystemExit(1) + if credentials: + try: + (keyid, keytype, passwd) = credentials.control(authkey) + except ValueError: + # There are no trusted keys. Barf. + log("cannot get authentication key") + raise SystemExit(1) + + if not credentials and authkey and keyfile is None: + sys.stderr.write("-a option requires -k.\n") + raise SystemExit(1) + + if not arguments: + arguments = ["localhost"] + + if replay: + (pkt, dst) = replay.split(":") + packet = ntp.packet.SyncPacket(pkt.decode("hex")) + packet.received = ntp.packet.SyncPacket.posix_to_ntp(float(dst)) + returned = [packet] + else: + returned = [] + needgap = (samples > 1) and (gap > 0) + firstloop = True + for s in range(samples): + if needgap and not firstloop: + time.sleep(gap) + if firstloop: + firstloop = False + for server in concurrent_hosts: + try: + returned += queryhost(server=server, + concurrent=True, + timeout=timeout, + bindaddr=bindaddr) + except ntp.packet.SyncException as e: + log(str(e)) + continue + for server in arguments: + try: + returned += queryhost(server=server, + concurrent=False, + timeout=timeout, + bindaddr=bindaddr) + except ntp.packet.SyncException as e: + log(str(e)) + continue + + returned = clock_select(returned) + + if returned: + pkt = returned[0] + if debug: + # print(repr(pkt)) + def hexstamp(n): + return "%08x.%08x" % (n >> 32, n & 0x00000000ffffffff) + print("org t1: %s rec t2: %s" + % (hexstamp(pkt.t1()), hexstamp(pkt.t2()))) + print("xmt t3: %s dst t4: %s" + % (hexstamp(pkt.t3()), hexstamp(pkt.t4()))) + pkt.posixize() + if debug: + print("org t1: %f rec t2: %f" % (pkt.t1(), pkt.t2())) + print("xmt t3: %f dst t4: %f" % (pkt.t3(), pkt.t4())) + print("rec-org t21: %f xmt-dst t34: %f" + % (pkt.t2() - pkt.t1(), pkt.t3() - pkt.t4())) + offset = pkt.adjust() + adjusted = (step and + (not slew or (slew and (abs(offset) > steplimit)))) + report(pkt, json) + # If we can step but we cannot slew, then step. + # If we can step or slew and |offset| > steplimit, then step. + rc = True + ntp.ntpc.setprogname("ntpdig") + if adjusted: + rc = ntp.ntpc.step_systime(offset) + elif slew: + rc = ntp.ntpc.adj_systime(offset) + if rc: + raise SystemExit(0) + else: + raise SystemExit(1) + else: + log("no eligible servers") + raise SystemExit(1) + except KeyboardInterrupt: + print("") + +# end \ No newline at end of file diff --git a/src/other-orgs.json b/src/other-orgs.json deleted file mode 100644 index 6d3c568..0000000 --- a/src/other-orgs.json +++ /dev/null @@ -1,169 +0,0 @@ -{ - "name": "Organisations", - "description": "Other organisations not under other another category", - "servers": [ - { - "name": "Cynergic", - "endpoints": [ - "ns2.cynergic.com.au", - "ns3.cynergic.com.au" - ] - }, - { - "name": "Conexim", - "endpoints": [ - "time.conexim.com.au", - "ns.conexim.com.au", - "ns1.conexim.com.au" - ] - }, - { - "name": "Comvergence", - "endpoints": [ - "ntp.comvergence.com.au", - "time.comvergence.com.au" - ] - }, - { - "name": "Sky News Australia", - "endpoints": [ - "ns.skynews.com.au" - ] - }, - { - "name": "Australia Online", - "endpoints": [ - "ntp.australiaonline.net.au", - "time.australiaonline.net.au" - ] - }, - { - "name": "ASE IT Networks", - "endpoints": [ - "time.aseit.com.au" - ] - }, - { - "name": "APCS", - "endpoints": [ - "ns1.apcs.com.au" - ] - }, - { - "name": "Dedicated Servers", - "endpoints": [ - "ntp.dedicatedservers.net.au" - ] - }, - { - "name": "Web in a Box", - "endpoints": [ - "ntp.webinabox.net.au" - ] - }, - { - "name": "Spectrum Networks", - "endpoints": [ - "ntp.spectrum.com.au", - "time.spectrum.com.au", - "ns2.spectrum.com.au" - ] - }, - { - "name": "Nexon", - "endpoints": [ - "ntp.nexon.com.au", - "ntp2.nexon.com.au", - "ns1.nexon.com.au" - ] - }, - { - "name": "KERNWIFI", - "endpoints": [ - "ntp.kernwifi.com.au", - "ntp2.kernwifi.com.au" - ] - }, - { - "name": "Interconnect Networks", - "endpoints": [ - "ntp.rbe.net.au" - ] - }, - { - "name": "Infinite Networks", - "endpoints": [ - "ntp.infinite.net.au" - ] - }, - { - "name": "Hostworks", - "endpoints": [ - "ntp.hostworks.com.au" - ] - }, - { - "name": "Host Tel", - "endpoints": [ - "ntp.hosttel.com.au", - "ns0.hosttel.com.au", - "ns1.hosttel.com.au", - "ns2.hosttel.com.au", - "ns4.hosttel.com.au" - ] - }, - { - "name": "GoHosting", - "endpoints": [ - "time.gohosting.com.au" - ] - }, - { - "name": "FetchTV", - "endpoints": [ - "ntp.fetchtv.com.au", - "0.fetchtv.pool.ntp.org" - ] - }, - { - "name": "EscapeNet", - "endpoints": [ - "ntp.esc.net.au", - "tic.esc.net.au", - "toc.esc.net.au" - ] - }, - { - "name": "ECN Internet", - "endpoints": [ - "ntp.ecn.net.au" - ] - }, - { - "name": "BitWave Networks", - "endpoints": [ - "ntp.bitwave.com.au" - ] - }, - { - "name": "Aus IT Services", - "endpoints": [ - "ntp.aus-it.com.au" - ] - }, - { - "name": "Internet Association of Australia", - "endpoints": [ - "ntp.asn.au", - "ntp.waia.asn.au" - ] - }, - { - "name": "connect.com.au", - "endpoints": [ - "ntp.connect.com.au", - "ntp.mel.connect.com.au" - ] - } - ] -} diff --git a/src/others.json b/src/others.json deleted file mode 100644 index bdaaa5d..0000000 --- a/src/others.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "Others", - "description": "Other individual servers not tied to a multi-server organisation", - "servers": [ - { "name": "", "endpoints": [ "syd4gps0.syd.ops.aspac.uu.net" ] }, - { "name": "", "endpoints": [ "vk6hgr.echidna.id.au" ] }, - { "name": "", "endpoints": [ "web02.anfiuwp.org.au" ] }, - { "name": "", "endpoints": [ "gw.vk6hgr.echidna.id.au" ] }, - { "name": "", "endpoints": [ "ntp.2000cn.com.au" ] }, - { "name": "", "endpoints": [ "ntp.mazzanet.net.au" ] }, - { "name": "", "endpoints": [ "ns1.git.au" ] }, - { "name": "", "endpoints": [ "ntp.polyfoam.com.au" ] }, - { "name": "", "endpoints": [ "smtp.juneks.com.au" ] }, - { "name": "", "endpoints": [ "time.9r.com.au" ] }, - { "name": "", "endpoints": [ "time.esec.com.au" ] }, - { "name": "", "endpoints": [ "mel.clearnet.pw" ] }, - { "name": "", "endpoints": [ "ntp1.ds.network" ] }, - { "name": "", "endpoints": [ "melbourne.kitten.im" ] }, - { "name": "", "endpoints": [ "pauseq4vntp1.datamossa.io" ] }, - { "name": "", "endpoints": [ "time.tfmcloud.au" ] }, - { "name": "", "endpoints": [ "svc4.eshorizon.net" ] }, - { "name": "", "endpoints": [ "syd.clearnet.pw" ] }, - { "name": "", "endpoints": [ "mansfield.id.au" ] }, - { "name": "", "endpoints": [ "ap-southeast-2.clearnet.pw" ] }, - { "name": "", "endpoints": [ "ntp-sydney.gombadi.com" ] } - ] -} diff --git a/src/test.py b/src/test.py new file mode 100644 index 0000000..0684518 --- /dev/null +++ b/src/test.py @@ -0,0 +1,19 @@ +from NtpDiscovery import NtpDiscovery +from NtpLookupCollection import NtpLookupCollection +import random + +coll = NtpLookupCollection.fromfile("data/lookups.json") +coll.validate() +coll._data = random.sample(coll._data, 50) +#coll._data = list(filter(lambda lc: lc.get_name() == "Hunter Water", coll._data)) + +print("Looking up {}".format(list(map(lambda l: l.get_name(), coll)))) + +disc = NtpDiscovery(coll) +report = disc.run() + +for item in report.generate_markdown(): + print("{}: {} -> {}".format(item["name"], item["endpoint"], ", ".join(map(lambda n: n.ip(), item["ntps"])))) + +with open("out.md", "w") as f: + f.write(report.get_markdown()) diff --git a/src/universities.json b/src/universities.json deleted file mode 100644 index 670a8cf..0000000 --- a/src/universities.json +++ /dev/null @@ -1,408 +0,0 @@ -{ - "name": "Universities", - "description": "Universities, Colleges, TAFEs, and other related institutions", - "servers": [ - { - "name": "Western Sydney University", - "endpoints": [ - "ntp.uws.edu.au", - "ntp1.uws.edu.au", - "ntp2.uws.edu.au", - "time.uws.edu.au", - "ns.uws.edu.au", - "ns1.uws.edu.au", - "ns2.uws.edu.au", - "ns3.uws.edu.au", - "ns4.uws.edu.au", - "ntp.westernsydney.edu.au", - "ntp2.westernsydney.edu.au", - "time.westernsydney.edu.au", - "ns.westernsydney.edu.au", - "ns1.westernsydney.edu.au", - "ns2.westernsydney.edu.au", - "ns3.westernsydney.edu.au", - "ns4.westernsydney.edu.au" - ] - }, - { - "name": "Victoria University", - "endpoints": [ - ] - }, - { - "name": "University of Woolongong", - "endpoints": [ - ] - }, - { - "name": "University of Tasmania", - "endpoints": [ - "ns1.utas.edu.au", - "ns2.utas.edu.au" - ] - }, - { - "name": "University of Sydney", - "endpoints": [ - "ntp.usyd.edu.au", - "ntp2.usyd.edu.au" - ] - }, - { - "name": "University of Southern Queensland", - "endpoints": [ - "ns0.usq.edu.au" - ] - }, - { - "name": "University of South Australia", - "endpoints": [ - "ns.unisa.edu.au", - "ns0.unisa.edu.au", - "ns1.unisa.edu.au", - "ns2.unisa.edu.au" - ] - }, - { - "name": "University of Notre Dame Australia", - "endpoints": [ - ] - }, - { - "name": "University of Newcastle", - "endpoints": [ - "ntp.newcastle.edu.au", - "time.newcastle.edu.au", - "ns.newcastle.edu.au", - "ns1.newcastle.edu.au", - "ns2.newcastle.edu.au" - ] - }, - { - "name": "Torrens University Australia", - "endpoints": [ - ] - }, - { - "name": "Southern Cross University", - "endpoints": [ - "ns.scu.edu.au" - ] - }, - { - "name": "Queensland University of Technology", - "endpoints": [ - "ns1.qut.edu.au", - "ns2.qut.edu.au", - "ns3.qut.edu.au", - "ns4.qut.edu.au" - ] - }, - { - "name": "Murdoch University", - "endpoints": [ - "ntp.murdoch.edu.au", - "ns1.murdoch.edu.au", - "ns2.murdoch.edu.au", - "ns3.murdoch.edu.au", - "ns4.murdoch.edu.au" - ] - }, - { - "name": "James Cook University", - "endpoints": [ - "ntp.jcu.edu.au", - "ntp1.jcu.edu.au", - "ntp2.jcu.edu.au", - "ns.jcu.edu.au", - "ns1.jcu.edu.au", - "ns2.jcu.edu.au", - "ns3.jcu.edu.au", - "ns4.jcu.edu.au" - ] - }, - { - "name": "Griffith University", - "endpoints": [ - "ns1.griffith.edu.au" - ] - }, - { - "name": "Flinders University", - "endpoints": [ - "ntp.flinders.edu.au" - ] - }, - { - "name": "Edith Cowan University", - "endpoints": [ - "ntp.ecu.edu.au", - "ntp1.ecu.edu.au", - "ntp2.ecu.edu.au", - "ns1.ecu.edu.au", - "ns2.ecu.edu.au" - ] - }, - { - "name": "Curtin University", - "endpoints": [ - "ntp.curtin.edu.au", - "time.curtin.edu.au", - "ns1.curtin.edu.au", - "ns2.curtin.edu.au", - "ns3.curtin.edu.au" - ] - }, - { - "name": "CQ University", - "endpoints": [ - "ntp.cqu.edu.au", - "ntp1.cqu.edu.au", - "ntp2.cqu.edu.au", - "ntp3.cqu.edu.au", - "ntp4.cqu.edu.au", - "ns1.cqu.edu.au", - "ns2.cqu.edu.au" - ] - }, - { - "name": "Charles Sturt University", - "endpoints": [ - "ntp.csu.edu.au", - "ns.csu.edu.au" - ] - }, - { - "name": "Charles Darwin University", - "endpoints": [ - "ntp.cdu.edu.au", - "ntp1.cdu.edu.au", - "ntp2.cdu.edu.au", - "ntp3.cdu.edu.au", - "ns1.cdu.edu.au", - "ns2.cdu.edu.au" - ] - }, - { - "name": "Avondale University", - "endpoints": [ - "ns0.avondale.edu.au", - "ns1.avondale.edu.au" - ] - }, - { - "name": "Bond University", - "endpoints": [ - "ntp.bond.edu.au" - ] - }, - { - "name": "Swinburne University", - "endpoints": [ - "ntp.swin.edu.au", - "ntp1.swin.edu.au", - "ntp2.swin.edu.au", - "ntp3.swin.edu.au", - "ns1.swin.edu.au", - "ns2.swin.edu.au", - "ns3.swin.edu.au", - "ns4.swin.edu.au" - ] - }, - { - "name": "Australian Catholic University", - "endpoints": [ - "ns.acu.edu.au", - "ns0.acu.edu.au", - "ns2.acu.edu.au" - ] - }, - { - "name": "University of the Sunshine Coast", - "endpoints": [ - "ntp.usc.edu.au", - "ntp1.usc.edu.au", - "ntp2.usc.edu.au", - "ntp3.usc.edu.au", - "ntp4.usc.edu.au" - ] - }, - { - "name": "University of Canberra", - "endpoints": [ - "ntp.canberra.edu.au", - "ntp1.canberra.edu.au", - "ntp2.canberra.edu.au", - "ntp3.canberra.edu.au", - "ntp4.canberra.edu.au", - "ns0.canberra.edu.au", - "ns1.canberra.edu.au", - "ns2.canberra.edu.au" - ] - }, - { - "name": "University of Wollongong", - "endpoints": [ - "ntp.uow.edu.au" - ] - }, - { - "name": "Macquarie University", - "endpoints": [ - "ntp.mq.edu.au", - "ntp1.mq.edu.au", - "ntp2.mq.edu.au", - "ntp3.mq.edu.au", - "ntp4.mq.edu.au", - "ntp5.mq.edu.au", - "time.mq.edu.au" - ] - }, - { - "name": "University of Queensland", - "endpoints": [ - "ntp.uq.edu.au", - "ntp1.uq.edu.au", - "ntp2.uq.edu.au" - ] - }, - { - "name": "University of New South Wales", - "endpoints": [ - "ntp.unsw.edu.au", - "ntp1.unsw.edu.au", - "ntp2.unsw.edu.au", - "ntp3.unsw.edu.au", - "ns1.unsw.edu.au", - "ns2.unsw.edu.au", - "ns3.unsw.edu.au" - ] - }, - { - "name": "University of Technology Sydney", - "endpoints": [ - "time.uts.edu.au", - "ns.uts.edu.au", - "ns1.uts.edu.au", - "ns2.uts.edu.au", - "ns3.uts.edu.au", - "ns4.uts.edu.au" - ] - }, - { - "name": "University of Divinity", - "endpoints": [ - ] - }, - { - "name": "LaTrobe University", - "endpoints": [ - "ntp.latrobe.edu.au", - "ntp1.latrobe.edu.au", - "ntp2.latrobe.edu.au", - "ntp4.latrobe.edu.au", - "ns0.latrobe.edu.au", - "ns1.latrobe.edu.au", - "ns2.latrobe.edu.au", - "ns3.latrobe.edu.au" - ] - }, - { - "name": "Federation University", - "endpoints": [ - "time.federation.edu.au" - ] - }, - { - "name": "University of Western Australia", - "endpoints": [ - "time.uwa.edu.au", - "ns.uwa.edu.au", - "ns1.uwa.edu.au", - "ns2.uwa.edu.au", - "ns3.uwa.edu.au" - ] - }, - { - "name": "University of Adelaide", - "endpoints": [ - "ntp.adelaide.edu.au", - "ntp1.adelaide.edu.au", - "ntp2.adelaide.edu.au", - "ns.adelaide.edu.au", - "ns1.adelaide.edu.au", - "ns2.adelaide.edu.au" - ] - }, - { - "name": "University of New England", - "endpoints": [ - "ntp.une.edu.au", - "tick.une.edu.au", - "tock.une.edu.au", - "ns.une.edu.au", - "ns1.une.edu.au", - "ns2.une.edu.au", - "ns3.une.edu.au" - ] - }, - { - "name": "RMIT University", - "endpoints": [ - "time.rmit.edu.au" - ] - }, - { - "name": "University of Melbourne", - "endpoints": [ - "ntp.unimelb.edu.au", - "ntp1.unimelb.edu.au", - "ntp2.unimelb.edu.au", - "ns1.unimelb.edu.au", - "ns2.unimelb.edu.au" - ] - }, - { - "name": "Deakin University", - "endpoints": [ - "ns1.deakin.edu.au", - "ns2.deakin.edu.au" - ] - }, - { - "name": "Monash University", - "endpoints": [ - "ntp.monash.edu.au", - "ntp1.monash.edu.au", - "ntp2.monash.edu.au", - "time.monash.edu.au", - "ns1.monash.edu.au", - "ns2.monash.edu.au", - "ns3.monash.edu.au", - "ns4.monash.edu.au", - "ntp1.net.monash.edu.au", - "ntp2.net.monash.edu.au" - ] - }, - { - "name": "Australian National University", - "endpoints": [ - "chronos.anu.edu.au", - "ntp.anu.edu.au", - "ntp1.anu.edu.au", - "ntp2.anu.edu.au", - "ntp3.anu.edu.au", - "ns1.anu.edu.au", - "ns2.anu.edu.au", - "ns3.anu.edu.au", - "ns4.anu.edu.au" - ] - }, - { - "name": "Christ Church Grammar School (Western Australia)", - "endpoints": [ - "leontp.ccgs.wa.edu.au" - ] - } - ] -} diff --git a/src/util.py b/src/util.py new file mode 100644 index 0000000..0791901 --- /dev/null +++ b/src/util.py @@ -0,0 +1,18 @@ +import dns.ipv4 +import ntp.packet +from .ntpdig import queryhost as ntpsec_ntpdig + +class util: + + @classmethod + def is_ipv4_addr(cls, s: str) -> bool: + try: + dns.ipv4.inet_aton(s) + return True + except: return False + + @classmethod + def ntpdig(cls, host: str, port: int = 123, timeout: int = 5) -> list[ntp.packet.SyncPacket]: + # raises socket.gaierror + #{'session': None, 'li_vn_mode': 36, '_Packet__extension': b'', 'status': 0, 'stratum': 3, 'poll': 3, 'precision': -24, 'root_delay': 1572, 'root_dispersion': 723, 'refid': 2851995649, 'reference_timestamp': 16873840357934835397, 'origin_timestamp': 16873840871369750528, 'receive_timestamp': 16873840872128219282, 'transmit_timestamp': 16873840872128333256, 'extfields': [], 'mac': '', 'hostname': 'ntp2.anu.edu.au', 'resolved': '150.203.22.28', 'received': 16873840871486769152, 'trusted': True, 'rescaled': False} + return ntpsec_ntpdig(host, True, timeout, port)