Merge branch 'master' of github.com:asmaps/nsupdate.info
This commit is contained in:
commit
39605becdb
20
docs/examples/bind9-nsupdate.info-zonefile
Normal file
20
docs/examples/bind9-nsupdate.info-zonefile
Normal file
@ -0,0 +1,20 @@
|
||||
$ORIGIN .
|
||||
$TTL 3600 ; 1 hour
|
||||
nsupdate.info IN SOA ns1.thinkmo.de. root.thinkmo.de. (
|
||||
2013093117 ; serial
|
||||
7200 ; refresh (2 hours)
|
||||
1800 ; retry (30 minutes)
|
||||
604800 ; expire (1 week)
|
||||
60 ; minimum (1 minute)
|
||||
)
|
||||
NS ns1.thinkmo.de.
|
||||
NS ns3.thinkmo.de.
|
||||
A 178.32.221.14
|
||||
AAAA 2001:41d0:8:e00e::1
|
||||
MX 10 mx.thinkmo.de.
|
||||
$ORIGIN nsupdate.info.
|
||||
$TTL 3600 ; 1 hour
|
||||
www A 178.32.221.14
|
||||
AAAA 2001:41d0:8:e00e::1
|
||||
ipv4 A 178.32.221.14
|
||||
ipv6 AAAA 2001:41d0:8:e00e::1
|
18
docs/examples/bind9-snippet
Normal file
18
docs/examples/bind9-snippet
Normal file
@ -0,0 +1,18 @@
|
||||
// configuration snippet for bind 9 nameserver (put it into /etc/bind9/named.conf )
|
||||
|
||||
key "nsupdate.info." {
|
||||
// must be same algorithm as in the nsupdate/nsupdate/settings.py
|
||||
algorithm hmac-sha512;
|
||||
// the secret is just a shared secret in base64-encoding, you don't need
|
||||
// to use a special tool to create it. Some random in base64 encoding should
|
||||
// be OK.
|
||||
secret "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ==";
|
||||
};
|
||||
|
||||
zone nsupdate.info {
|
||||
type master;
|
||||
// bind9 needs write permissions into that directory and into that file:
|
||||
file "/etc/bind/zones/nsupdate.info";
|
||||
// everyone who has that key may update this zone:
|
||||
allow-update { key "nsupdate.info."; };
|
||||
};
|
@ -198,6 +198,14 @@ def AuthorizedNicUpdateView(request):
|
||||
|
||||
def _update(hostname, ipaddr):
|
||||
ipaddr = str(ipaddr) # XXX bug in dnspython: crashes if ipaddr is unicode, wants a str!
|
||||
hosts = Host.filter_by_fqdn(hostname)
|
||||
num_hosts = len(hosts)
|
||||
if num_hosts == 0:
|
||||
return False
|
||||
if num_hosts > 1:
|
||||
logging.error("fqdn %s has multiple entries" % hostname)
|
||||
return False
|
||||
hosts[0].poke()
|
||||
try:
|
||||
update(hostname, ipaddr)
|
||||
logger.info('%s - received good update -> ip: %s' % (hostname, ipaddr, ))
|
||||
|
89
nsupdate/main/migrations/0009_added_last_api_update_field.py
Normal file
89
nsupdate/main/migrations/0009_added_last_api_update_field.py
Normal file
@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Adding field 'Host.last_api_update'
|
||||
db.add_column(u'main_host', 'last_api_update',
|
||||
self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True),
|
||||
keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
# Deleting field 'Host.last_api_update'
|
||||
db.delete_column(u'main_host', 'last_api_update')
|
||||
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
u'main.blacklisteddomain': {
|
||||
'Meta': {'object_name': 'BlacklistedDomain'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'domain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_update': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'main.domain': {
|
||||
'Meta': {'object_name': 'Domain'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']", 'null': 'True', 'blank': 'True'}),
|
||||
'domain': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_update': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
|
||||
},
|
||||
u'main.host': {
|
||||
'Meta': {'unique_together': "(('subdomain', 'domain'),)", 'object_name': 'Host'},
|
||||
'comment': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'null': 'True', 'blank': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts'", 'to': u"orm['auth.User']"}),
|
||||
'domain': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['main.Domain']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_api_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_update': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'subdomain': ('django.db.models.fields.CharField', [], {'max_length': '256'}),
|
||||
'update_secret': ('django.db.models.fields.CharField', [], {'max_length': '256'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
@ -6,6 +6,8 @@ from django.conf import settings
|
||||
from django.db.models.signals import post_delete
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from main import dnstools
|
||||
import dns.resolver
|
||||
from datetime import datetime
|
||||
|
||||
import re
|
||||
|
||||
@ -55,6 +57,7 @@ class Host(models.Model):
|
||||
max_length=256, default='', blank=True, null=True)
|
||||
|
||||
last_update = models.DateTimeField(auto_now=True)
|
||||
last_api_update = models.DateTimeField(blank=True, null=True)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
created_by = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, related_name='hosts')
|
||||
@ -78,6 +81,22 @@ class Host(models.Model):
|
||||
return Host.objects.filter(
|
||||
subdomain=splitted[0], domain__domain=splitted[1], **kwargs)
|
||||
|
||||
def getIPv4(self):
|
||||
try:
|
||||
return dnstools.query_ns(self.get_fqdn(), 'A')
|
||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||
return '-'
|
||||
|
||||
def getIPv6(self):
|
||||
try:
|
||||
return dnstools.query_ns(self.get_fqdn(), 'AAAA')
|
||||
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
|
||||
return '-'
|
||||
|
||||
def poke(self):
|
||||
self.last_api_update = datetime.now()
|
||||
self.save()
|
||||
|
||||
def generate_secret(self):
|
||||
# note: we use a quick hasher for the update_secret as expensive
|
||||
# more modern hashes might put too much load on the servers. also
|
||||
|
@ -34,6 +34,21 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<h3>General Information</h3>
|
||||
<p>We try to get your IP addresses through a trick. We host two fake images on a IPv4 and IPv6 domain and we can associate those with your session. If we find an IP address, we will update this information accordingly. This allows us to get your IPv4 address even when you are using your IPv6 and vice versa.</p>
|
||||
<b>your IPv4:</b> <span class="ipv4adr">{{ request.session.ipv4 }}</span> <br>
|
||||
<b>your IPv6:</b> <span class="ipv6adr">{{ request.session.ipv6 }}</span>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h3>Host Information</h3>
|
||||
<p>This information comes directly from the name server and shows the current IPs set for your domain.</p>
|
||||
<b>Host IPv4:</b> <span class="ipv4adr">{{ host.getIPv4 }}</span> <br>
|
||||
<b>Host IPv6:</b> <span class="ipv6adr">{{ host.getIPv6 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
@ -3,14 +3,16 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="col-lg-9">
|
||||
<h3>Host List</h3>
|
||||
<table class="table">
|
||||
<tr><th>domain</th><th>last update</th><th>comment</th><th>action</th></tr>
|
||||
<tr><th>domain</th><th>last IP update</th><th>IPv4</th><th>IPv6</th><th>comment</th><th>action</th></tr>
|
||||
{% for host in hosts %}
|
||||
<tr>
|
||||
<td><b>{{ host.subdomain }}.{{ host.domain.domain }}</b></td>
|
||||
<td>{{ host.last_update|date }}</td>
|
||||
<td>{{ host.last_update|timesince }}</td>
|
||||
<td>{{ host.getIPv4 }}</td>
|
||||
<td>{{ host.getIPv6 }}</td>
|
||||
<td>{{ host.comment }}</td>
|
||||
<td>
|
||||
<a href="{% url 'host_view' host.pk %}"><i class="icon icon-pencil"></i> edit</a> |
|
||||
@ -22,7 +24,7 @@
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="col-lg-3">
|
||||
<h3>New Host</h3>
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
@ -31,9 +33,11 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="col-lg-6">
|
||||
<h3>Information</h3>
|
||||
<p>We try to get your IP addresses through a trick. We host two fake images on a IPv4 and IPv6 domain and we can associate those with your session. If we find an IP address, we will update this information accordingly. This allows us to get your IPv4 address even when you are using your IPv6 and vice versa.</p>
|
||||
<b>your IPv4:</b> <span class="ipv4adr">{{ request.session.ipv4 }}</span> <br>
|
||||
<b>your IPv6:</b> <span class="ipv6adr">{{ request.session.ipv6 }}</span>
|
||||
</div>
|
||||
|
@ -1,7 +1,8 @@
|
||||
from django.conf.urls import patterns, url
|
||||
from django.views.generic import TemplateView
|
||||
from main.views import (
|
||||
HomeView, OverviewView, HostView, DeleteHostView, AboutView, HelpView, GenerateSecretView)
|
||||
HomeView, OverviewView, HostView, DeleteHostView, AboutView, HelpView, GenerateSecretView,
|
||||
RobotsTxtView, )
|
||||
from api.views import (
|
||||
MyIpView, DetectIpView, NicUpdateView, AuthorizedNicUpdateView)
|
||||
|
||||
@ -23,4 +24,5 @@ urlpatterns = patterns(
|
||||
url(r'^nic/update$', NicUpdateView),
|
||||
url(r'^nic/update_authorized$',
|
||||
AuthorizedNicUpdateView, name='nic_update_authorized'),
|
||||
url(r'^robots.txt$', RobotsTxtView),
|
||||
)
|
||||
|
@ -1,13 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.views.generic import TemplateView, CreateView
|
||||
from django.views.generic.edit import UpdateView, DeleteView
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib import messages
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.exceptions import PermissionDenied
|
||||
import dns.inet
|
||||
import dnstools
|
||||
|
||||
from main.forms import CreateHostForm, EditHostForm
|
||||
from main.models import Host
|
||||
@ -88,6 +89,7 @@ class OverviewView(CreateView):
|
||||
self.object = form.save(commit=False)
|
||||
self.object.created_by = self.request.user
|
||||
self.object.save()
|
||||
dnstools.add(self.object.get_fqdn(), self.request.META['REMOTE_ADDR'])
|
||||
messages.add_message(self.request, messages.SUCCESS, 'Host added.')
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
@ -152,3 +154,21 @@ class DeleteHostView(DeleteView):
|
||||
context['nav_overview'] = True
|
||||
context['hosts'] = Host.objects.filter(created_by=self.request.user)
|
||||
return context
|
||||
|
||||
|
||||
def RobotsTxtView(request):
|
||||
"""
|
||||
Dynamically serve robots.txt content.
|
||||
If you like, you can optimize this by statically serving this by your web server.
|
||||
|
||||
:param request: django request object
|
||||
:return: HttpResponse object
|
||||
"""
|
||||
content = """\
|
||||
User-agent: *
|
||||
Crawl-delay: 10
|
||||
Disallow: /accounts/
|
||||
Disallow: /myip/
|
||||
Disallow: /nic/update/
|
||||
"""
|
||||
return HttpResponse(content, content_type="text/plain")
|
||||
|
Loading…
x
Reference in New Issue
Block a user