From b3c85a4c4028624bbc2e6215a12a90272cb49fd1 Mon Sep 17 00:00:00 2001 From: darthsandmann Date: Sun, 18 Dec 2022 16:13:50 +0100 Subject: [PATCH] first commit --- .dcignore | 1547 +++++++++++++++++ .github/workflows/go.yml | 51 + .gitignore | 5 + .golangci.yaml | 26 + .goreleaser.yaml | 39 + LICENSE | 21 + Makefile | 60 + README.md | 54 + go.mod | 17 + go.sum | 33 + licenses/github.com/go-ping/ping/LICENSE | 21 + licenses/github.com/google/uuid/LICENSE | 27 + .../github.com/mattn/go-colorable/LICENSE | 21 + licenses/github.com/mattn/go-isatty/LICENSE | 9 + licenses/github.com/rs/zerolog/LICENSE | 21 + licenses/golang.org/x/net/LICENSE | 27 + licenses/golang.org/x/sync/errgroup/LICENSE | 27 + licenses/golang.org/x/sys/LICENSE | 27 + main.go | 150 ++ 19 files changed, 2183 insertions(+) create mode 100644 .dcignore create mode 100644 .github/workflows/go.yml create mode 100644 .gitignore create mode 100644 .golangci.yaml create mode 100644 .goreleaser.yaml create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 licenses/github.com/go-ping/ping/LICENSE create mode 100644 licenses/github.com/google/uuid/LICENSE create mode 100644 licenses/github.com/mattn/go-colorable/LICENSE create mode 100644 licenses/github.com/mattn/go-isatty/LICENSE create mode 100644 licenses/github.com/rs/zerolog/LICENSE create mode 100644 licenses/golang.org/x/net/LICENSE create mode 100644 licenses/golang.org/x/sync/errgroup/LICENSE create mode 100644 licenses/golang.org/x/sys/LICENSE create mode 100644 main.go diff --git a/.dcignore b/.dcignore new file mode 100644 index 0000000..9dc099e --- /dev/null +++ b/.dcignore @@ -0,0 +1,1547 @@ +# Write glob rules for ignored files. +# Check syntax on https://deepcode.freshdesk.com/support/solutions/articles/60000531055-how-can-i-ignore-files-or-directories- +# Check examples on https://github.com/github/gitignore + +# Hidden directories +.*/ + +# FuelPHP +/fuel/vendor +/docs/ +/fuel/app/logs/*/*/* +/fuel/app/cache/*/* + +# Godot +data_*/ + +# Lilypond +*~ + +# Nim +nimcache/ +nimblecache/ +htmldocs/ + +# Android +bin/ +gen/ +out/ +build/ +proguard/ +captures/ +freeline/ +fastlane/screenshots +fastlane/test_output +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ + +# UnrealEngine +Binaries/* +Plugins/*/Binaries/* +Build/* +!Build/*/ +Build/*/** +Saved/* +Intermediate/* +Plugins/*/Intermediate/* +DerivedDataCache/* + +# Zephir +ext/build/ +ext/modules/ +ext/Makefile* +ext/config* +ext/autom4te* +ext/install-sh +ext/missing +ext/mkinstalldirs +ext/libtool + +# Typo3 +/fileadmin/user_upload/ +/fileadmin/_temp_/ +/fileadmin/_processed_/ +/uploads/ +/typo3conf/temp_CACHED* +/typo3conf/ENABLE_INSTALL_TOOL +/FIRST_INSTALL +/typo3 +/Packages +/typo3temp/ + +# Actionscript +bin-debug/ +bin-release/ +[Oo]bj/ +[Bb]in/ + +# WordPress +!wp-content/ +wp-content/* +!wp-content/mu-plugins/ +!wp-content/plugins/ +!wp-content/themes/ +wp-content/themes/twenty*/ +node_modules/ + +# Lithium +libraries/* +resources/tmp/* + +# Python +__pycache__/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +MANIFEST +htmlcov/ +cover/ +instance/ +docs/_build/ +target/ +profile_default/ +__pypackages__/ +celerybeat-schedule +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +/site +cython_debug/ + +# VVVV +bin/ + +# CodeIgniter +*/config/development +*/cache/* +application/logs/* +/vendor/ + +# AppEngine +appengine-generated/ + +# Objective-C +xcuserdata/ +build/ +DerivedData/ +Carthage/Build/ +fastlane/test_output +iOSInjectionProject/ + +# GWT +war/gwt_bree/ +gwt-unitCache/ +war/WEB-INF/deploy/ +war/WEB-INF/classes/ +www-test/ + +# Delphi +__history/ +__recovery/ +modules/ + +# ROS +devel/ +logs/ +build/ +bin/ +lib/ +msg_gen/ +srv_gen/ +build_isolated/ +devel_isolated/ +/cfg/cpp/ +qtcreator-* +/planning/cfg +/planning/docs +*~ +CATKIN_IGNORE + +# Stella +obj/ + +# Jekyll +_site/ + +# MetaProgrammingSystem +classes_gen +source_gen +test_gen + +# JENKINS_HOME +!/jobs +jobs/** +!jobs/**/ +builds +indexing +jobs/**/*workspace + +# Leiningen +/lib/ +/classes/ +/target/ +/checkouts/ + +# Laravel +/vendor/ +node_modules/ +app/storage/ +public/storage +public/hot +public_html/storage +public_html/hot + +# R +/*.Rcheck/ +*_cache/ +/cache/ +docs/ +po/*~ + +# Processing +applet +out + +# GitBook +node_modules +_book + +# LemonStand +/config/* +/controllers/* +/init/* +/logs/* +/phproad/* +/temp/* +/uploaded/* +/installer_files/* +/modules/backend/* +/modules/blog/* +/modules/cms/* +/modules/core/* +/modules/session/* +/modules/shop/* +/modules/system/* +/modules/users/* + +# ArchLinuxPackages +pkg/ + +# Swift +xcuserdata/ +build/ +DerivedData/ +Carthage/Build/ +Dependencies/ +fastlane/test_output +iOSInjectionProject/ + +# Packer +packer_cache/ + +# Elixir +/_build +/cover +/deps +/doc + +# Phalcon +/cache/ +/config/development/ + +# Unity +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ +/[Mm]emoryCaptures/ +/[Aa]ssets/Plugins/Editor/JetBrains* +ExportedObj/ +/[Aa]ssets/[Ss]treamingAssets/aa/* + +# Scrivener +*/QuickLook/ + +# Kohana +application/cache/* +application/logs/* + +# Prestashop +/cache/* +!/cache/push/activity +!/cache/push/trends +/download/* +/img/* +!/img/jquery-ui +!/img/scenes +/upload/* +/vendor/* +/docs/phpdoc-sf/ +/admin-dev/autoupgrade/* +/admin-dev/backups/* +/admin-dev/import/* +/admin-dev/export/* +themes/*/cache/* +config/xml/* +config/themes/* +modules/* +override/* +themes/*/ +!themes/classic +!themes/_core +!themes/_libraries +bower_components/ +node_modules/ +php-cs-fixer +translations/* +mails/* +!mails/themes/ +!mails/_partials/ +themes/default-bootstrap/lang/* +themes/default-bootstrap/mails/* +!themes/default-bootstrap/mails/en/ +themes/default-bootstrap/modules/*/mails/* +!themes/default-bootstrap/modules/*/mails/en +/bin/ +/app/Resources/translations/* +!/app/Resources/translations/default +/build/ +/var/* +!/var/cache +/var/cache/* +!/var/logs +/var/logs/* +!/var/sessions +/var/sessions/* +/vendor/ +/web/bundles/ + +# ExtJs +build/ +ext/ + +# CMake +CMakeFiles +CMakeScripts +Testing +Makefile +_deps + +# Umbraco +**/App_Data/Logs/ +**/App_Data/[Pp]review/ +**/App_Data/TEMP/ +**/App_Data/NuGetBackup/ +!**/App_Data/[Pp]ackages/* +!**/[Uu]mbraco/[Dd]eveloper/[Pp]ackages/* +!**/[Uu]mbraco/[Vv]iews/[Pp]ackages/* +**/App_Data/cache/ + +# CakePHP +/vendor/* +/tmp/cache/models/* +!/tmp/cache/models/empty +/tmp/cache/persistent/* +!/tmp/cache/persistent/empty +/tmp/cache/views/* +!/tmp/cache/views/empty +/tmp/sessions/* +!/tmp/sessions/empty +/tmp/tests/* +!/tmp/tests/empty +/logs/* +!/logs/empty +/app/tmp/* +/vendors/* + +# Java +hs_err_pid* + +# Symfony +/app/cache/* +/app/logs/* +/app/spool/* +/var/cache/* +/var/logs/* +/var/sessions/* +/var/log/* +/bin/* +!bin/console +!bin/symfony_requirements +/vendor/ +/web/bundles/ +/web/uploads/ +/build/ +**/Entity/*~ + +# Composer +/vendor/ + +# SymphonyCMS +manifest/cache/ +manifest/logs/ +manifest/tmp/ +symphony/ +workspace/uploads/ + +# JBoss6 +/server/all/data +/server/all/log +/server/all/tmp +/server/all/work +/server/default/data +/server/default/log +/server/default/tmp +/server/default/work +/server/minimal/data +/server/minimal/log +/server/minimal/tmp +/server/minimal/work +/server/jbossweb-standalone/data +/server/jbossweb-standalone/log +/server/jbossweb-standalone/tmp +/server/jbossweb-standalone/work +/server/standard/data +/server/standard/log +/server/standard/tmp +/server/standard/work + +# JBoss4 +/server/all/data +/server/all/log +/server/all/tmp +/server/all/work +/server/default/data +/server/default/log +/server/default/tmp +/server/default/work +/server/minimal/data +/server/minimal/log +/server/minimal/tmp +/server/minimal/work + +# Red +quick-test/runnable/ +system/tests/source/units/auto-tests/ +tests/source/units/auto-tests/ + +# Snap +parts/ +prime/ +stage/ + +# Splunk +local + +# Hugo +/public/ +/resources/_gen/ + +# Bazel +/bazel-* + +# Nikola +cache/ +output/ + +# JupyterNotebooks +profile_default/ + +# Puppet +pkg/* +spec/fixtures/* +coverage/* +vendor/* + +# Racket +compiled/ + +# Phoenix +/tmp +/node_modules +/assets/node_modules +/priv/static/ +/installer/_build +/installer/tmp +/installer/doc +/installer/deps + +# Logtalk +lgt_tmp/ +logtalk_tester_logs/ +logtalk_doclet_logs/ + +# NWjs +locales/ +pnacl/ + +# Cordova +/platforms + +# Vue +docs/_book +test/ + +# Kentico +!CMS/CMSAdminControls/*/ +!CMS/CMSModules/System/*/ +!CMS/App_Data/CIRepository/** +CMS/App_Data/AzureCache +CMS/App_Data/AzureTemp +CMS/App_Data/CMSTemp +CMS/App_Data/Persistent +CMS/CMSSiteUtils/Export +CMS/CMSSiteUtils/Import +CMS/App_Data/CMSModules/SmartSearch/** +!CMS/App_Data/CMSModules/SmartSearch/*/ +!CMS/App_Data/CMSModules/SmartSearch/_StopWords/** +!CMS/App_Data/CMSModules/SmartSearch/_Synonyms/** +CMS/App_Data/DancingGoat +CMS/App_Data/Templates/CommunitySite +CMS/App_Data/Templates/CorporateSite +CMS/App_Data/Templates/DancingGoat +CMS/App_Data/Templates/EcommerceSite +CMS/App_Data/Templates/IntranetPortal +CMS/App_Data/Templates/PersonalSite +CMS/App_Themes/CommunitySite +CMS/App_Themes/CorporateSite +CMS/App_Themes/EcommerceSite +CMS/App_Themes/IntranetPortal* +CMS/App_Themes/PersonalSite +CMS/CMSTemplates/CorporateSite +CMS/CommunitySite +CMS/CorporateSite +CMS/DancingGoat +CMS/EcommerceSite +CMS/IntranetPortal +CMS/PersonalSite + +# InforCMS +[Mm]odel/[Dd]eployment +!Model/Portal/*/SupportFiles/[Bb]in/ +!Model/Portal/PortalTemplates/*/SupportFiles/[Bb]in + +# Xilinx +*_synth_* +*/*/bd/*/hdl +*/*/*/bd/*/hdl +*/*/bd/*/ip/*/*/ +*/*/*/bd/*/ip/*/*/ +hw_handoff +ipshared + +# Pimcore +/pimcore +/website/var/assets/* +/website/var/backup/* +/website/var/cache/* +/website/var/classes/Object* +!/website/var/classes/objectbricks +/website/var/config/Geo* +/website/var/config/object/* +/website/var/config/portal/* +/website/var/config/sqlreport/* +/website/var/email/* +/website/var/recyclebin/* +/website/var/search/* +/website/var/system/* +/website/var/tmp/* +/website/var/versions/asset/* +/website/var/versions/document/* +/website/var/versions/object/* +/website/var/user-image/* + +# Magento2 +/sitemap +/pub/sitemap +/app/config_sandbox +/app/code/Magento/TestModule* +/pub/media/attribute/* +/pub/media/analytics/* +/pub/media/catalog/* +/pub/media/customer/* +/pub/media/downloadable/* +/pub/media/favicon/* +/pub/media/import/* +/pub/media/logo/* +/pub/media/theme/* +/pub/media/theme_customization/* +/pub/media/wysiwyg/* +/pub/media/tmp/* +/pub/media/captcha/* +/pub/static/* +/var/* +/vendor/* +/generated/* + +# Bitrix +/bitrix/* +!/bitrix/templates +!/bitrix/components +/bitrix/components/bitrix +!/bitrix/gadgets +/bitrix/gadgets/bitrix +!/bitrix/php_interface/ +/upload/ + +# Drupal7 +files/ +sites/*/files +sites/*/private +sites/*/translations +/includes +/misc +/modules +/profiles +/scripts +/themes + +# CodeSniffer +/wpcs/* + +# Jigsaw +build_* + +# Magento1 +/media/* +!/media/customer +/media/customer/* +!/media/dhl +/media/dhl/* +!/media/downloadable +/media/downloadable/* +!/media/xmlconnect +/media/xmlconnect/* +!/media/xmlconnect/custom +/media/xmlconnect/custom/* +!/media/xmlconnect/original +/media/xmlconnect/original/* +!/media/xmlconnect/system +/media/xmlconnect/system/* +/var/* +!/var/package +/var/package/* + +# ThinkPHP +/Application/Runtime/ + +# AtmelStudio +[Dd]ebug/ +[Rr]elease/ + +# IAR_EWARM +EWARM/**/Obj +EWARM/**/List +EWARM/**/Exe +EWARM/settings + +# esp-idf +build/ +sdkconfig + +# Concrete5 +error_log +files/cache/* +files/tmp/* +/application/files/* +/updates/* + +# Drupal +/sites/*/files +/sites/*/public +/sites/*/private +/sites/*/files-public +/sites/*/files-private +/sites/*/translations +/sites/*/tmp +/sites/*/cache +/sites/simpletest +/core +/vendor + +# Mercury +Mercury/ + +# Joomla +/administrator/cache/* +/administrator/components/com_actionlogs/* +/administrator/components/com_admin/* +/administrator/components/com_ajax/* +/administrator/components/com_associations/* +/administrator/components/com_banners/* +/administrator/components/com_cache/* +/administrator/components/com_categories/* +/administrator/components/com_checkin/* +/administrator/components/com_config/* +/administrator/components/com_contact/* +/administrator/components/com_content/* +/administrator/components/com_contenthistory/* +/administrator/components/com_cpanel/* +/administrator/components/com_fields/* +/administrator/components/com_finder/* +/administrator/components/com_installer/* +/administrator/components/com_joomlaupdate/* +/administrator/components/com_languages/* +/administrator/components/com_login/* +/administrator/components/com_media/* +/administrator/components/com_menus/* +/administrator/components/com_messages/* +/administrator/components/com_modules/* +/administrator/components/com_newsfeeds/* +/administrator/components/com_plugins/* +/administrator/components/com_postinstall/* +/administrator/components/com_privacy/* +/administrator/components/com_redirect/* +/administrator/components/com_search/* +/administrator/components/com_tags/* +/administrator/components/com_templates/* +/administrator/components/com_users/* +/administrator/help/* +/administrator/includes/* +/administrator/language/overrides/* +/administrator/logs/* +/administrator/modules/mod_custom/* +/administrator/modules/mod_feed/* +/administrator/modules/mod_latest/* +/administrator/modules/mod_latestactions/* +/administrator/modules/mod_logged/* +/administrator/modules/mod_login/* +/administrator/modules/mod_menu/* +/administrator/modules/mod_multilangstatus/* +/administrator/modules/mod_online/* +/administrator/modules/mod_popular/* +/administrator/modules/mod_privacy_dashboard/* +/administrator/modules/mod_quickicon/* +/administrator/modules/mod_sampledata/* +/administrator/modules/mod_stats_admin/* +/administrator/modules/mod_status/* +/administrator/modules/mod_submenu/* +/administrator/modules/mod_title/* +/administrator/modules/mod_toolbar/* +/administrator/modules/mod_unread/* +/administrator/modules/mod_version/* +/administrator/templates/hathor/* +/administrator/templates/isis/* +/administrator/templates/system/* +/bin/* +/cache/* +/cli/* +/components/com_ajax/* +/components/com_banners/* +/components/com_config/* +/components/com_contact/* +/components/com_content/* +/components/com_contenthistory/* +/components/com_fields/* +/components/com_finder/* +/components/com_mailto/* +/components/com_media/* +/components/com_menus/* +/components/com_modules/* +/components/com_newsfeeds/* +/components/com_privacy/* +/components/com_search/* +/components/com_tags/* +/components/com_users/* +/components/com_wrapper/* +/images/banners/* +/images/headers/* +/images/sampledata/* +/images/joomla* +/includes/* +/installation/* +/language/overrides/* +/layouts/joomla/* +/layouts/libraries/* +/layouts/plugins/* +/libraries/cms/* +/libraries/fof/* +/libraries/idna_convert/* +/libraries/joomla/* +/libraries/legacy/* +/libraries/php-encryption/* +/libraries/phpass/* +/libraries/phpmailer/* +/libraries/phputf8/* +/libraries/simplepie/* +/libraries/vendor/* +/media/cms/* +/media/com_associations/* +/media/com_contact/* +/media/com_content/* +/media/com_contenthistory/* +/media/com_fields/* +/media/com_finder/* +/media/com_joomlaupdate/* +/media/com_menus/* +/media/com_modules/* +/media/com_wrapper/* +/media/contacts/* +/media/editors/* +/media/jui/* +/media/mailto/* +/media/media/* +/media/mod_languages/* +/media/mod_sampledata/* +/media/overrider/* +/media/plg_captcha_recaptcha/* +/media/plg_captcha_recaptcha_invisible/* +/media/plg_quickicon_extensionupdate/* +/media/plg_quickicon_joomlaupdate/* +/media/plg_quickicon_privacycheck/* +/media/plg_system_highlight/* +/media/plg_system_stats/* +/media/plg_twofactorauth_totp/* +/media/system/* +/modules/mod_articles_archive/* +/modules/mod_articles_categories/* +/modules/mod_articles_category/* +/modules/mod_articles_latest/* +/modules/mod_articles_news/* +/modules/mod_articles_popular/* +/modules/mod_banners/* +/modules/mod_breadcrumbs/* +/modules/mod_custom/* +/modules/mod_feed/* +/modules/mod_finder/* +/modules/mod_footer/* +/modules/mod_languages/* +/modules/mod_login/* +/modules/mod_menu/* +/modules/mod_random_image/* +/modules/mod_related_items/* +/modules/mod_search/* +/modules/mod_stats/* +/modules/mod_syndicate/* +/modules/mod_tags_popular/* +/modules/mod_tags_similar/* +/modules/mod_users_latest/* +/modules/mod_whosonline/* +/modules/mod_wrapper/* +/plugins/actionlog/joomla/* +/plugins/authentication/cookie/* +/plugins/authentication/example/* +/plugins/authentication/gmail/* +/plugins/authentication/joomla/* +/plugins/authentication/ldap/* +/plugins/captcha/recaptcha/* +/plugins/captcha/recaptcha_invisible/* +/plugins/content/confirmconsent/* +/plugins/content/contact/* +/plugins/content/emailcloak/* +/plugins/content/example/* +/plugins/content/fields/* +/plugins/content/finder/* +/plugins/content/geshi/* +/plugins/content/joomla/* +/plugins/content/loadmodule/* +/plugins/content/pagebreak/* +/plugins/content/pagenavigation/* +/plugins/content/vote/* +/plugins/editors/codemirror/* +/plugins/editors/none/* +/plugins/editors/tinymce/* +/plugins/editors-xtd/article/* +/plugins/editors-xtd/contact/* +/plugins/editors-xtd/fields/* +/plugins/editors-xtd/image/* +/plugins/editors-xtd/menu/* +/plugins/editors-xtd/module/* +/plugins/editors-xtd/pagebreak/* +/plugins/editors-xtd/readmore/* +/plugins/extension/example/* +/plugins/extension/joomla/* +/plugins/fields/calendar/* +/plugins/fields/checkboxes/* +/plugins/fields/color/* +/plugins/fields/editor/* +/plugins/fields/imagelist/* +/plugins/fields/integer/* +/plugins/fields/list/* +/plugins/fields/media/* +/plugins/fields/radio/* +/plugins/fields/repeatable/* +/plugins/fields/sql/* +/plugins/fields/text/* +/plugins/fields/textarea/* +/plugins/fields/url/* +/plugins/fields/user/* +/plugins/fields/usergrouplist/* +/plugins/finder/categories/* +/plugins/finder/contacts/* +/plugins/finder/content/* +/plugins/finder/newsfeeds/* +/plugins/finder/tags/* +/plugins/installer/folderinstaller/* +/plugins/installer/packageinstaller/* +/plugins/installer/urlinstaller/* +/plugins/privacy/actionlogs/* +/plugins/privacy/consents/* +/plugins/privacy/contact/* +/plugins/privacy/content/* +/plugins/privacy/message/* +/plugins/privacy/user/* +/plugins/quickicon/extensionupdate/* +/plugins/quickicon/joomlaupdate/* +/plugins/quickicon/phpversioncheck/* +/plugins/quickicon/privacycheck/* +/plugins/sampledata/blog/* +/plugins/search/categories/* +/plugins/search/contacts/* +/plugins/search/content/* +/plugins/search/newsfeeds/* +/plugins/search/tags/* +/plugins/search/weblinks/* +/plugins/system/actionlogs/* +/plugins/system/cache/* +/plugins/system/debug/* +/plugins/system/fields/* +/plugins/system/highlight/* +/plugins/system/languagecode/* +/plugins/system/languagefilter/* +/plugins/system/log/* +/plugins/system/logout/* +/plugins/system/logrotation/* +/plugins/system/p3p/* +/plugins/system/privacyconsent/* +/plugins/system/redirect/* +/plugins/system/remember/* +/plugins/system/sef/* +/plugins/system/sessiongc/* +/plugins/system/stats/* +/plugins/system/updatenotification/* +/plugins/twofactorauth/totp/* +/plugins/twofactorauth/yubikey/* +/plugins/user/contactcreator/* +/plugins/user/example/* +/plugins/user/joomla/* +/plugins/user/profile/* +/plugins/user/terms/* +/templates/beez3/* +/templates/protostar/* +/templates/system/* +/tmp/* + +# Yii +assets/* +protected/runtime/* +themes/classic/views/ + +# Rust +debug/ +target/ + +# Node +logs +pids +lib-cov +coverage +bower_components +build/Release +node_modules/ +jspm_packages/ +web_modules/ +out +dist + +# PureScript +bower_components +node_modules +output + +# JBoss +jboss/server/all/tmp/**/* +jboss/server/all/data/**/* +jboss/server/all/work/**/* +jboss/server/default/tmp/**/* +jboss/server/default/data/**/* +jboss/server/default/work/**/* +jboss/server/minimal/tmp/**/* +jboss/server/minimal/data/**/* +jboss/server/minimal/work/**/* + +# Grails +/web-app/WEB-INF/classes +/test/reports +/logs +/plugins +/web-app/plugins +/target + +# C +*.dSYM/ + +# ZendFramework +vendor/ +data/logs/ +data/cache/ +data/sessions/ +data/tmp/ +temp/ +data/DoctrineORMModule/Proxy/ +data/DoctrineORMModule/cache/ +demos/ +extras/documentation + +# PlayFramework +bin/ +/db +/lib/ +/logs/ +/modules +/project/project +/project/target +/target +tmp/ +test-result +/dist/ + +# SugarCRM +/cache/* +/custom/history/ +/custom/modulebuilder/ +/custom/working/ +/custom/modules/*/Ext/ +/custom/application/Ext/ +/upload/* +/upload_backup/ + +# ExpressionEngine +images/avatars/ +images/captchas/ +images/smileys/ +images/member_photos/ +images/signature_attachments/ +images/pm_attachments/ +sized/ +thumbs/ +_thumbs/ +*/expressionengine/cache/* + +# KiCad +*~ +_autosave-* +fp-info-cache + +# Plone +bin/ +build/ +develop-eggs/ +downloads/ +eggs/ +fake-eggs/ +parts/ +dist/ +var/ + +# D +docs/ + +# CFWheels +plugins/**/* +files +db/sql +javascripts/bundles +stylesheets/bundles + +# Yeoman +node_modules/ +bower_components/ +build/ +dist/ + +# Nanoc +output/ +tmp/nanoc/ + +# Erlang +rel/example_project +deps +_build/ +_checkouts/ + +# VisualStudio +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ +Generated\ Files/ +[Tt]est[Rr]esult*/ +[Dd]ebugPS/ +[Rr]eleasePS/ +BenchmarkDotNet.Artifacts/ +artifacts/ +_Chutzpah* +ipch/ +$tf/ +_ReSharper*/ +_TeamCity* +_NCrunch_* +nCrunchTemp_* +AutoTest.Net/ +[Ee]xpress/ +DocProject/buildhelp/ +DocProject/Help/Html2 +DocProject/Help/html +publish/ +PublishScripts/ +**/[Pp]ackages/* +!**/[Pp]ackages/build/ +csx/ +ecf/ +rcf/ +AppPackages/ +BundleArtifacts/ +!?*.[Cc]ache/ +ClientBin/ +~$* +*~ +Generated_Code/ +_UpgradeReport_Files/ +Backup*/ +ServiceFabricBackup/ +FakesAssemblies/ +node_modules/ +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.Server/GeneratedArtifacts +_Pvt_Extensions +paket-files/ +__pycache__/ +OpenCover/ +ASALocalRun/ +healthchecksdb +MigrationBackup/ + +# Perl +!Build/ +cover_db/ +_build/ +Build +inc/ +/blib/ +/_eumm/ +/Makefile +/pm_to_blib + +# OCaml +_build/ +_opam/ + +# Agda +MAlonzo/** + +# Clojure +/lib/ +/classes/ +/target/ +/checkouts/ + +# OpenCart +download/ +image/data/ +image/cache/ +system/cache/ +system/logs/ +system/storage/ +vqmod/logs/* +vqmod/vqcache/* + +# Kotlin +hs_err_pid* + +# Julia +deps/downloads/ +deps/usr/ +docs/build/ +docs/site/ + +# Opa +_build +_tracks +opa-debug-js + +# Windows +$RECYCLE.BIN/ + +# MonoDevelop +test-results/ + +# JDeveloper +temp/ +classes/ +deploy/ +javadoc/ + +# CodeKit +/min + +# VirtualEnv +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ll]ocal +[Ss]cripts + +# Tags +TAGS +!TAGS/ +tags +!tags/ +GTAGS +GRTAGS +GPATH +GSYMS + +# Virtuoso +lvsRunDir/* +drcRunDir/* + +# PSoCCreator +Debug/ +Release/ +Export/ +*/codegentemp +*/Generated_Source + +# Calabash +rerun/ +reports/ +screenshots/ +test-servers/ +vendor + +# TextMate +tmtags + +# Lazarus +backup/ +lib/ +*.app/ + +# macOS +Icon + +Network Trash Folder +Temporary Items + +# EiffelStudio +EIFGENs + +# MATLAB +helpsearch*/ +slprj/ +sccprj/ +codegen/ +octave-workspace + +# FlexBuilder +bin/ +bin-debug/ +bin-release/ + +# Eclipse +bin/ +tmp/ + +# Vim +*~ +tags + +# SynopsysVCS +simv +simv.daidir/ +simv.db.dir/ +simv.vdb/ +urgReport/ +DVEfiles/ + +# Emacs +*~ +\#*\# +auto-save-list +tramp +*_archive +/eshell/history +/eshell/lastdir +/elpa/ +/auto/ +dist/ +/server/ + +# Momentics +x86/ +arm/ +arm-p/ + +# Linux +*~ + +# SublimeText +Package Control.cache/ +Package Control.ca-certs/ + +# CVS +/CVS/* +**/CVS/* + +# Dreamweaver +_notes +_compareTemp +configs/ + +# Xcode +xcuserdata/ +build/ +DerivedData/ + +# WebMethods +**/IntegrationServer/datastore/ +**/IntegrationServer/db/ +**/IntegrationServer/DocumentStore/ +**/IntegrationServer/lib/ +**/IntegrationServer/logs/ +**/IntegrationServer/replicate/ +**/IntegrationServer/sdk/ +**/IntegrationServer/support/ +**/IntegrationServer/update/ +**/IntegrationServer/userFtpRoot/ +**/IntegrationServer/web/ +**/IntegrationServer/WmRepository4/ +**/IntegrationServer/XAStore/ +**/IntegrationServer/packages/Wm*/ + +# ModelSim +[_@]* +wlf* +cov*/ +transcript* + +# NetBeans +**/nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ + +# JetBrains +cmake-build-*/ +out/ + +# Octave +helpsearch*/ +slprj/ +sccprj/ +codegen/ +octave-workspace + +# SBT +dist/* +target/ +lib_managed/ +project/boot/ +project/plugins/project/ + +# XilinxISE +iseconfig/ +xlnx_auto_0_xdb/ +xst/ +_ngo/ +_xmsgs/ + +# Smalltalk +/package-cache +/play-cache +/play-stash +/github-cache + +# Magento +/media/* +!/media/customer +/media/customer/* +!/media/dhl +/media/dhl/* +!/media/downloadable +/media/downloadable/* +!/media/xmlconnect +/media/xmlconnect/* +!/media/xmlconnect/custom +/media/xmlconnect/custom/* +!/media/xmlconnect/original +/media/xmlconnect/original/* +!/media/xmlconnect/system +/media/xmlconnect/system/* +/var/* +!/var/package +/var/package/* + +# TurboGears2 +data/* +dist +build + +# ChefCookbook +/cookbooks +bin/* + +# TeX +latex.out/ +*-gnuplottex-* +*-tikzDictionary +_minted* +sympy-plots-for-*.tex/ +pythontex-files-*/ +TSWLatexianTemp* +*~[0-9]* + +# Rails +/public/system +/coverage/ +/spec/tmp +/log/* +/tmp/* +/vendor/bundle +/vendor/assets/bower_components +node_modules/ +/public/packs +/public/packs-test +/public/assets +/storage/* +/public/uploads + +# Dart +build/ +doc/api/ + +# Ruby +/coverage/ +/InstalledFiles +/pkg/ +/spec/reports/ +/test/tmp/ +/test/version_tmp/ +/tmp/ +build/ +build-iPhoneOS/ +build-iPhoneSimulator/ +/_yardoc/ +/doc/ +/rdoc/ +/vendor/bundle +/lib/bundler/man/ + +# Textpattern +rpc/ +sites/site*/admin/ +sites/site*/private/ +sites/site*/public/admin/ +sites/site*/public/setup/ +sites/site*/public/theme/ +textpattern/ + +# Autotools +/ar-lib +/mdate-sh +/py-compile +/test-driver +/ylwrap +/compile +/configure +/depcomp +/install-sh +/missing +/stamp-h1 +Makefile + +# Qooxdoo +cache +cache-downloads +inspector +api + +# Maven +target/ + +# Waf +waf-*-*/ +waf3-*-*/ + +# Qt +Makefile* +*build-* + +# ForceDotCom +Referenced Packages + +# SeamGen +/bootstrap/data +/bootstrap/tmp +/classes/ +/dist/ +/exploded-archives/ +/test-build/ +/test-output/ +/test-report/ +/target/ + +# RhodesRhomobile +rholog-* +sim-* +bin/libs +bin/RhoBundle +bin/tmp +bin/target + +# Xojo +Builds* +Debug*/Debug*\ Libs + +# Haskell +dist +dist-* +cabal-dev + +# Elm +elm-stuff +repl-temp-* + +# AppceleratorTitanium +build/ + +# CraftCMS +/craft/storage/* +!/craft/storage/rebrand + +# Gradle +**/build/ + +# Elisp +*~ diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 0000000..155586f --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,51 @@ +name: Go + +on: + push: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.17 + + - name: Test + run: go test -v ./... + + - name: Lint source code + run: | + make tools lint + rm -rf .bin/ + rm -rf dist/ + + - name: Set up Git actions user + uses: fregante/setup-git-user@v1 + + - name: Collect and save licenses + run: | + go install github.com/google/go-licenses@latest + rm -rf licenses + go-licenses save . --save_path="licenses" --ignore "github.com/bastiandoetsch/mullvad-best-server" + git add licenses + git commit -m "Updated licenses" && git push || echo "No changes to commit" + git clean -f && git reset --hard + + - name: Create release tag + run: | + git tag "v$(git show -s --format=%cd --date=format:%Y%m%d.%H%M%S)" + git push --tags + + - name: Release binaries with GoReleaser + uses: goreleaser/goreleaser-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + args: release --rm-dist diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f35717 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +dist/ +.idea +*.iml +*.eml \ No newline at end of file diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..d51b61b --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,26 @@ +linters: + disable-all: true + enable: + - deadcode + - errcheck + - gofmt + - goimports + - gosimple + - ineffassign + - misspell + - staticcheck + - structcheck + - unconvert + - unused + - varcheck + - govet + +linters-settings: + goimports: + local-prefixes: github.com/bastiandoetsch/mullvad-best-server + +output: + format: tab + +run: + deadline: 10m diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..e06e836 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,39 @@ +project_name: mullvad-best-server + +before: + hooks: + - go mod tidy + +builds: + - flags: + - -trimpath + env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + mod_timestamp: "{{ .CommitTimestamp }}" + +archives: + - replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + format: binary + name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + +checksum: + name_template: 'checksums.txt' + +snapshot: + name_template: "{{ incpatch .Version }}-next" + +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..44d1862 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Bastian Doetsch + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1cbe263 --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ +# project variables +PROJECT_NAME := mullvad-best-server + +# build variables +.DEFAULT_GOAL = lint +BUILD_DIR := dist +DEV_GOARCH := $(shell go env GOARCH) +DEV_GOOS := $(shell go env GOOS) + + +## tools: Install required tooling. +.PHONY: tools +tools: +ifeq (,$(wildcard ./.bin/golangci-lint*)) + @curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b .bin/ v1.44.2 +else + @echo "==> Required tooling is already installed" +endif + +## clean: Delete the build directory +.PHONY: clean +clean: + @echo "==> Removing '$(BUILD_DIR)' directory..." + @rm -rf $(BUILD_DIR) + +## lint: Lint code with golangci-lint. +.PHONY: lint +lint: tools + @echo "==> Linting code with 'golangci-lint'..." + @.bin/golangci-lint run ./... + +## test: Run all unit tests. +.PHONY: test +test: + @echo "==> Running unit tests..." + @mkdir -p $(BUILD_DIR) + @go test -count=1 -v -cover -coverprofile=$(BUILD_DIR)/coverage.out -parallel=4 ./... + +## build: Build binary for default local system's OS and architecture. +.PHONY: build +build: + @echo "==> Building binary..." + @echo " running go build for GOOS=$(DEV_GOOS) GOARCH=$(DEV_GOARCH)" +# workaround for missing .exe extension on Windows +ifeq ($(OS),Windows_NT) + @go build -o $(BUILD_DIR)/$(PROJECT_NAME).$(DEV_GOOS).$(DEV_GOARCH).exe +else + @go build -o $(BUILD_DIR)/$(PROJECT_NAME).$(DEV_GOOS).$(DEV_GOARCH) +endif + +.PHONY: run +run: + @echo "==> Running $(PROJECT_NAME)" + @go run main.go + +help: Makefile + @echo "Usage: make " + @echo "" + @echo "Commands:" + @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' diff --git a/README.md b/README.md new file mode 100644 index 0000000..1bb7235 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# mullvad-best-server +![Build](https://github.com/bastiandoetsch/mullvad-best-server/actions/workflows/go.yml/badge.svg) + +Determines the mullvad.net server with the lowest latency on macOS and Linux. On Windows, it can only check if the server is up. +The reason lies with the golang network libraries, according to the `go-ping` library, that is used under the hood for pinging: + +``` +Please note that accessing packet TTL values is not supported due to limitations in the Go x/net/ipv4 and x/net/ipv6 packages. +``` + +## Installation + +Download binary from releases for your platform and unpack. + +## Usage +### Default usage +Execute `mullvad-best-server`. It outputs the code, e.g. `de05`. You can then connect to it with e.g. wireguard using the normal shell scripts. + +### Command line parameters + +```angular2html +Usage of dist/mullvad-best-server_darwin_amd64/mullvad-best-server: +-c string + Server country code, e.g. ch for Switzerland (default "ch") +-l string + Log level. Allowed values: trace, debug, info, warn, error, fatal, panic (default "info") +-o string + Output format. 'json' outputs server json +-t string + Server type, e.g. wireguard (default "wireguard") +``` + +If you want the full server information, execute `mullvad-best-server -o json`. It returns the full json output of the server information. +The `-c` flag allows to give a country code. Else `ch` will be used. + + +## Background +The program uses `https://api.mullvad.net/www/relays//` to get the current server list, pings the ones with the right country +and outputs the server with the lowest ping. + +## Integration into a script +I use it on my router like this (yes, I know I could have done the whole thing with jq and shell scripting, but wanted to use go for maintainability). +``` +#!/bin/sh +set -e +LATEST_RELEASE=$(curl -sSL https://api.github.com/repos/bastiandoetsch/mullvad-best-server/releases/latest | jq -r '.assets[]| .browser_download_url' | grep Linux_arm64) +curl -sSL $LATEST_RELEASE > /root/mullvad-best-server +chmod +x /root/mullvad-best-server +/usr/bin/wg-quick down $(wg show|grep interface | cut -d: -f2) || echo "nothing to shut down" +/usr/bin/wg-quick up "mullvad-$(/root/mullvad-best-server -c de)" +``` + +## Troubleshooting +You may have to update your `/usr/bin/wg-quick` script for the new mullvad servers, as they have names longer than 15 chars. Replace `[[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15} ]]$` with `[[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,25}$ ]]` and `[[ $CONFIG_FILE =~ (^|/)([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]]` with `[[ $CONFIG_FILE =~ (^|/)([a-zA-Z0-9_=+.-]{1,25})\.conf$ ]]` diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..878064b --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module github.com/bastiandoetsch/mullvad-best-server + +go 1.17 + +require ( + github.com/go-ping/ping v1.1.0 + github.com/rs/zerolog v1.27.0 +) + +require ( + github.com/google/uuid v1.3.0 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 // indirect + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c3f1d54 --- /dev/null +++ b/go.sum @@ -0,0 +1,33 @@ +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw= +github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs= +github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 h1:UreQrH7DbFXSi9ZFox6FNT3WBooWmdANpU+IfkT1T4I= +golang.org/x/net v0.0.0-20220728211354-c7608f3a8462/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/licenses/github.com/go-ping/ping/LICENSE b/licenses/github.com/go-ping/ping/LICENSE new file mode 100644 index 0000000..5584bb0 --- /dev/null +++ b/licenses/github.com/go-ping/ping/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Cameron Sparr and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/github.com/google/uuid/LICENSE b/licenses/github.com/google/uuid/LICENSE new file mode 100644 index 0000000..5dc6826 --- /dev/null +++ b/licenses/github.com/google/uuid/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009,2014 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/github.com/mattn/go-colorable/LICENSE b/licenses/github.com/mattn/go-colorable/LICENSE new file mode 100644 index 0000000..91b5cef --- /dev/null +++ b/licenses/github.com/mattn/go-colorable/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/github.com/mattn/go-isatty/LICENSE b/licenses/github.com/mattn/go-isatty/LICENSE new file mode 100644 index 0000000..65dc692 --- /dev/null +++ b/licenses/github.com/mattn/go-isatty/LICENSE @@ -0,0 +1,9 @@ +Copyright (c) Yasuhiro MATSUMOTO + +MIT License (Expat) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/licenses/github.com/rs/zerolog/LICENSE b/licenses/github.com/rs/zerolog/LICENSE new file mode 100644 index 0000000..677e07f --- /dev/null +++ b/licenses/github.com/rs/zerolog/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Olivier Poitrey + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/licenses/golang.org/x/net/LICENSE b/licenses/golang.org/x/net/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/licenses/golang.org/x/net/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/golang.org/x/sync/errgroup/LICENSE b/licenses/golang.org/x/sync/errgroup/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/licenses/golang.org/x/sync/errgroup/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/licenses/golang.org/x/sys/LICENSE b/licenses/golang.org/x/sys/LICENSE new file mode 100644 index 0000000..6a66aea --- /dev/null +++ b/licenses/golang.org/x/sys/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/main.go b/main.go new file mode 100644 index 0000000..a9b5af4 --- /dev/null +++ b/main.go @@ -0,0 +1,150 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "io/ioutil" + "net/http" + "runtime" + "strings" + "time" + + "github.com/go-ping/ping" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +func main() { + var outputFlag = flag.String("o", "", "Output format. 'json' outputs server json") + var countryFlag = flag.String("c", "ch", "Server country code, e.g. ch for Switzerland") + var typeFlag = flag.String("t", "wireguard", "Server type, e.g. wireguard") + var logLevel = flag.String("l", "info", "Log level. Allowed values: trace, debug, info, warn, error, fatal, panic") + var ownedFlag = flag.String("m", "true", "Server owned by Mullvad") + flag.Parse() + + level, err := zerolog.ParseLevel(*logLevel) + if err != nil { + log.Fatal().Err(err).Msg("Unable to set log level") + } + zerolog.SetGlobalLevel(level) + servers := getServers(*typeFlag) + bestIndex := selectBestServerIndex(servers, *countryFlag, *ownedFlag) + if bestIndex == -1 { + log.Fatal().Str("country", *countryFlag).Msg("No servers for country found.") + } + best := servers[bestIndex] + log.Debug().Interface("server", best).Msg("Best latency server found.") + hostname := strings.TrimSuffix(best.Hostname, "-wireguard") + if *outputFlag != "json" { + fmt.Println(hostname) + } else { + serverJson, err := json.Marshal(best) + if err != nil { + log.Fatal().Err(err).Msg("Couldn't marshal server information to Json") + } + fmt.Println(string(serverJson)) + } +} + +func getOwned(ownedInput string) bool { + if ownedInput == "true" { + return true + } else { + return false + } +} + +func selectBestServerIndex(servers []server, country string, ownedInput string) int { + bestIndex := -1 + var bestPing time.Duration + for i, server := range servers { + if getOwned(ownedInput) == true { + if server.Active && server.CountryCode == country && server.Owned == true { + duration, err := serverLatency(server) + if err == nil { + if bestIndex == -1 || bestPing > duration { + bestIndex = i + bestPing = duration + } + } else { + log.Err(err).Msg("Error determining the server latency via ping.") + } + } + } else { + if server.Active && server.CountryCode == country { + duration, err := serverLatency(server) + if err == nil { + if bestIndex == -1 || bestPing > duration { + bestIndex = i + bestPing = duration + } + } else { + log.Err(err).Msg("Error determining the server latency via ping.") + } + } + } + + } + return bestIndex +} + +func getServers(serverType string) []server { + resp, err := http.Get("https://api.mullvad.net/www/relays/" + serverType + "/") + if err != nil { + log.Fatal().Err(err).Msg("Couldn't retrieve servers") + } + responseBody, err := ioutil.ReadAll(resp.Body) + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + log.Err(err) + } + }(resp.Body) + if err != nil { + log.Fatal().Err(err) + } + var servers []server + err = json.Unmarshal(responseBody, &servers) + if err != nil { + log.Fatal().Err(err).Msg("couldn't unmarshall server json") + } + return servers +} + +//goland:noinspection GoBoolExpressions +func serverLatency(s server) (time.Duration, error) { + pinger, err := ping.NewPinger(s.Ipv4AddrIn) + if runtime.GOOS == "windows" { + pinger.SetPrivileged(true) + } + pinger.Count = 1 + if err != nil { + return 0, err + } + var duration time.Duration + pinger.OnRecv = func(pkt *ping.Packet) { + log.Debug().Str("Server", s.Hostname).IPAddr("IP", pkt.IPAddr.IP).Dur("RTT", pkt.Rtt).Msg("Added server latency.") + duration = pkt.Rtt + } + err = pinger.Run() + return duration, err +} + +type server struct { + Hostname string `json:"hostname"` + CountryCode string `json:"country_code"` + CountryName string `json:"country_name"` + CityCode string `json:"city_code"` + CityName string `json:"city_name"` + Active bool `json:"active"` + Owned bool `json:"owned"` + Provider string `json:"provider"` + Ipv4AddrIn string `json:"ipv4_addr_in"` + Ipv6AddrIn string `json:"ipv6_addr_in"` + NetworkPortSpeed int `json:"network_port_speed"` + Pubkey string `json:"pubkey"` + MultihopPort int `json:"multihop_port"` + SocksName string `json:"socks_name"` +}