Commit ce32a12e authored by Alexander Blair's avatar Alexander Blair
Browse files

Update to Python3 script

parent e93c77cd
# Created by https://www.gitignore.io/api/pycharm,python
### PyCharm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### PyCharm Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# 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/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
# End of https://www.gitignore.io/api/pycharm,python
config.json
\ No newline at end of file
{
"loop": true,
"delay": 300,
"debug": false,
"zones": {
"domain-mainnet": {
"domain": "domain.com",
"provider": "cloudflare",
"login": "your_email_here",
"password": "312089eh2938",
"subdomain": "mainnet",
"rpc_host": "127.0.0.1",
"rpc_port": "18081",
"required_port": "18080"
},
"domain-testnet": {
"domain": "domain.com",
"provider": "cloudflare",
"login": "your_email_here",
"password": "312089eh2938",
"subdomain": "testnet",
"rpc_host": "127.0.0.1",
"rpc_port": "28081",
"required_port": "28080"
}
}
}
\ No newline at end of file
<?php
// Copyright (c) 2014, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the copyright holder 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 HOLDER 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.
// Install from Pear: pear install XML_RPC2
require_once 'XML/RPC2/Client.php';
// Included in package
require_once 'jsonrpclib.php';
use JsonRPC\Client;
echo "Starting...";
// Everything is wrapped in a try catch with no error handling, as it's ok if seed data is a little out of date
try
{
// Gandi.net API key
$apikey = 'PUTYOURAPIKEYHERE'; // Put your API key here
// The ID of the zone (when editing a zone in Gandi you can see the ID in the URL, it's the number after /admin/domain/zone/
$zoneid = 000000; // Put the zone ID you're editing here
// Connect to local Monero instance and call get_connections
$monerorpc = new Client('http://127.0.0.1:18081/json_rpc');
$peerconnections = $monerorpc->execute('get_connections');
// Build up a list of active peer IPs that (seem to) allow inbound connections
$peerlist = array();
foreach ($peerconnections['connections'] as $peer)
{
// Filter out anything not on port 18080 (we can't have ports in A records, and this also precludes most peers that don't allow incoming connections)
// Also filter out anything not in "state_normal" (eg. pre-handshake or similar)
if (($peer['port'] == 18080) && ($peer['state'] == 'state_normal'))
{
$peerlist[] = $peer['ip'];
}
}
// Setup our RPC clients for Gandi: zone records, domain info, zone versioning
$record_api = XML_RPC2_Client::create('https://rpc.gandi.net/xmlrpc/',
array( 'prefix' => 'domain.zone.record.', 'sslverify' => false )
);
$zone_api = XML_RPC2_Client::create('https://rpc.gandi.net/xmlrpc/',
array( 'prefix' => 'domain.zone.', 'sslverify' => false )
);
$version_api = XML_RPC2_Client::create('https://rpc.gandi.net/xmlrpc/',
array( 'prefix' => 'domain.zone.version.', 'sslverify' => false )
);
// Check what zone version we're currently on (Gandi doesn't let you edit the current zone version)
$allzones = $zone_api->list($apikey);
foreach ($allzones as $zone)
{
if ($zone['id'] == $zoneid)
{
// Store this, as we're going to work in a new zone and then switch
$oldzoneversion = $zone['version'];
}
}
// This is extremely hacky and assumes you have zone version 3 and 4 already created and ready for everything (except for the seeds.* A records, which are
// deleted as necessary and then created to match the peerlist). This is just fine for our purposes, but useless for anyone else that doesn't configure this
// appropriately on Gandi.
if ($oldzoneversion == 3)
{
$zoneversion = 4;
}
else
{
$zoneversion = 3;
}
echo $zoneversion."...";
// Grab the zone records *from the version we're editing* (we don't care about the currently active zone version, we're going to switch away from it)
$zonerecords = $record_api->list($apikey, $zoneid, $zoneversion);
// Step through the zone records and delete all of the seed.* records
foreach ($zonerecords as $record)
{
if ($record['name'] == 'seeds')
{
$deleterecord = $record_api->delete($apikey, $zoneid, $zoneversion, array('id' => $record['id']));
}
}
array_unique($peerlist);
// Take our new peer list and add them as A records
foreach ($peerlist as $peerip)
{
// It's a seeds.* A record, value is our peer IP address, and the TTL is 5 minutes
$addrecord = $record_api->add($apikey, $zoneid, $zoneversion, array(
'name' => 'seeds',
'type' => 'A',
'value' => $peerip,
'ttl' => 300,
));
}
// Finally, switch zone versions to this new version we've created
$switchzones = $version_api->set($apikey, $zoneid, $zoneversion);
echo "Done!\n";
}
catch (Exception $e)
{
// In the event we encounter an error (eg. Gandi is unavailable, seeds are unavailable) do nothing, we're going to retry in 5 minutes
echo 'Caught exception: ', $e->getMessage(), "\n";
}
?>
#!/bin/bash
# Copyright (c) 2014, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder 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 HOLDER 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.
while true
do
php ~/xmr-seeder/dns_poll.php &
sleep 300
done
#!/usr/bin/which python3
import requests
import json
import sys
import time
import socket
class CloudFlareDNS:
real_zone, zone_id = [None, None]
def __init__(self, login, password, zone, debug=False):
import CloudFlare
self.cf = CloudFlare.CloudFlare(email=login, token=password, debug=debug)
self.zone = zone
self.debug = debug
self.get_zone_id()
def get_current_entries(self, subdomain):
dns_records = self.cf.zones.dns_records.get(self.zone_id)
record_list = {}
for dns_record in dns_records:
if self.debug:
print(dns_record)
if dns_record['name'] == "{}.{}".format(subdomain, self.zone):
record_list[dns_record['id']] = dns_record['content']
return record_list
def get_zone_id(self):
zones = self.cf.zones.get(params={'name': self.zone})
if self.debug:
print("Zones response: {}".format(zones))
if len(zones) == 0:
raise ValueError("Invalid zone name")
self.real_zone = zones[0]
self.zone_id = self.real_zone['id']
if self.debug:
print("Zone ID for {} is {}".format(self.zone, self.zone_id))
def update_zones(self, entries, subdomain):
if self.debug:
print("Updating DNS with: {}".format(entries))
for k, v in self.get_current_entries(subdomain).items():
if k not in entries['current'].keys():
print("Removing DNS entry: {} for IP {}".format(k, v))
self.cf.zones.dns_records.delete(k)
for new_ip in entries['new']:
print("Adding DNS entry for IP {}".format(new_ip))
self.cf.zones.dns_records.post(self.zone_id,
data={'type': 'A', 'name': "{}.{}".format(subdomain, self.zone),
'content': new_ip, 'ttl': 300, 'proxied': False})
def test_p2p_connectivity(ip, port):
s = socket.socket()
return_state = False
try:
s.connect((ip, int(port)))
return_state = True
except Exception as e:
print("Unable to connect to {}:{} exception is: {}".format(ip, port, e))
finally:
s.close()
return return_state
def process_update(zone_data, debug=False):
print("Starting run on: {}.{}".format(zone_data['subdomain'], zone_data['domain']))
if zone_data['provider'] == 'cloudflare':
try:
dns_provider = CloudFlareDNS(zone_data['login'], zone_data['password'], zone_data['domain'], debug)
except:
raise
else:
print("{} is an invalid DNS provider! Aborting!".format(zone_data['provider']))
sys.exit(1)
current_entries = dns_provider.get_current_entries(zone_data['subdomain'])
entry_list = {'current': {}, 'new': []}
current_ips = []
if len(current_entries) > 0:
for ip_id, ip in current_entries.items():
if test_p2p_connectivity(ip, zone_data['required_port']):
entry_list['current'][ip_id] = ip
current_ips.append(ip)
daemon_data = requests.post("http://{}:{}/json_rpc".format(zone_data['rpc_host'], zone_data['rpc_port']),
data=json.dumps({"jsonrpc": "2.0", "id": "0", "method": "get_connections"}),
headers={"Content-Type": "application/json"})
if daemon_data.status_code == 200:
if debug:
print(daemon_data.json())
for connection in daemon_data.json()['result']['connections']:
if connection['ip'] in current_ips:
print("Ignoring: {}:{} as the IP is in the current list".format(connection['ip'],
connection['port']))
continue
if connection['state'] != "state_normal":
print("Ignoring: {}:{} as the state is: {}".format(connection['ip'],
connection['port'],
connection['state']))
continue
if connection['port'] != zone_data['required_port']:
print("Ignoring: {}:{} as the port is not: {}".format(connection['ip'],
connection['port'],
zone_data['required_port']))
continue
if not test_p2p_connectivity(connection['ip'], zone_data['required_port']):
print("Ignoring: {}:{} unable to connect to: {}".format(connection['ip'],
connection['port'],
zone_data['required_port']))
entry_list['new'].append(connection['ip'])
dns_provider.update_zones(entry_list, zone_data['subdomain'])
print("Run complete on: {}.{} new entry count: {}".format(zone_data['subdomain'], zone_data['domain'],
len(entry_list['new']) + len(entry_list['current'])))
def main():
with open('config.json', 'r') as f:
config = json.load(f)
if len(sys.argv) == 1:
print("Need to select a zone, or all!")
sys.exit(1)
if len(sys.argv) == 2 and sys.argv[1] not in config['zones'] and sys.argv[1] != 'all':
print("{} not configured for DNS update! Aborting!".format(sys.argv[1]))
sys.exit(1)
while True:
try:
if sys.argv[1] == 'all':
for k, v in config['zones'].items():
process_update(v, config['debug'])
else:
process_update(config['zones'][sys.argv[1]], config['debug'])
except Exception as e:
print("Hit exception: {}".format(e))
if config['loop'] is False:
break
time.sleep(config['delay'])
main()
#!/bin/bash
# Copyright (c) 2014, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. 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.
#
# 3. Neither the name of the copyright holder 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 HOLDER 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.
if ! pgrep dns_poll.sh > /dev/null
then
screen -S xmr-seeder -d -m ~/xmr-seeder/dns_poll.sh
fi
<?php
namespace JsonRPC;
/**
* JsonRPC client class
*
* @package JsonRPC
* @author Frderic Guillot
* @license Unlicense http://unlicense.org/
*/
class Client
{
/**
* URL of the server
*
* @access private
* @var string
*/
private $url;
/**
* HTTP client timeout
*
* @access private
* @var integer
*/
private $timeout;
/**
* Debug flag
*
* @access private
* @var bool
*/
private $debug;
/**
* Username for authentication
*
* @access private
* @var string
*/
private $username;
/**
* Password for authentication
*
* @access private
* @var string
*/
private $password;
/**
* Default HTTP headers to send to the server
*
* @access private
* @var array
*/
private $headers = array(
'Connection: close',
'Content-Type: application/json',
'Accept: application/json'
);
/**
* Constructor
*
* @access public
* @param string $url Server URL
* @param integer $timeout Server URL
* @param bool $debug Debug flag
* @param array $headers Custom HTTP headers
*/
public function __construct($url, $timeout = 5, $debug = false, $headers = array())
{
$this->url = $url;
$this->timeout = $timeout;
$this->debug = $debug;
$this->headers = array_merge($this->headers, $headers);
}
/**
* Automatic mapping of procedures
*
* @access public
* @param string $method Procedure name
* @param array $params Procedure arguments
* @return mixed
*/
public function __call($method, $params)
{
return $this->execute($method, $params);
}
/**
* Set authentication parameters
*
* @access public
* @param string $username Username
* @param string $password Password
*/
public function authentication($username, $password)
{
$this->username = $username;
$this->password = $password;
}
/**
* Execute
*