From 1022a018e1e5c0dbfcc5e1e5ac63e0013666b5b9 Mon Sep 17 00:00:00 2001 From: Michael Ziegler Date: Mon, 23 Nov 2009 15:30:20 +0100 Subject: [PATCH] validate that the address and port are available by trying to bind when saving a new server instance. fixes #57 --- pyweb/mumble/admin.py | 2 ++ pyweb/mumble/forms.py | 43 +++++++++++++++++++++++++++++++++++++++++- pyweb/mumble/models.py | 6 +++--- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/pyweb/mumble/admin.py b/pyweb/mumble/admin.py index f009014..83cd4e2 100644 --- a/pyweb/mumble/admin.py +++ b/pyweb/mumble/admin.py @@ -17,6 +17,7 @@ from django.contrib import admin from django.utils.translation import ugettext_lazy as _ +from forms import MumbleAdminForm from models import * class MumbleAdmin(admin.ModelAdmin): @@ -24,6 +25,7 @@ class MumbleAdmin(admin.ModelAdmin): list_filter = [ 'booted', 'addr' ]; search_fields = [ 'name', 'addr' ]; ordering = [ 'name' ]; + form = MumbleAdminForm; def getUsersRegged( self, obj ): return obj.users_regged; diff --git a/pyweb/mumble/forms.py b/pyweb/mumble/forms.py index 60068c5..60a85f1 100644 --- a/pyweb/mumble/forms.py +++ b/pyweb/mumble/forms.py @@ -14,6 +14,7 @@ * GNU General Public License for more details. """ +import socket import re from django import forms @@ -27,7 +28,47 @@ class MumbleAdminForm( ModelForm ): """ A Mumble Server admin form intended to be used by the server hoster. """ class Meta: model = Mumble; - exclude = ( 'sslcrt', 'sslkey' ); + + def clean_port( self ): + port = self.cleaned_data['port']; + if port == -1: + port = max( [ rec['port'] for rec in Mumble.objects.values('port') ] ) + 1; + + if port < 1 or port >= 2**16: + raise forms.ValidationError( + _("Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d") % { + 'portno': port, + 'minrange': 1, + 'maxrange': 2**16, + }); + return port; + + def clean( self ): + if self.instance.id is not None or 'addr' not in self.cleaned_data or 'port' not in self.cleaned_data: + # Editing old instance or previous validation failed already, don't try to bind + return self.cleaned_data; + + # Try to bind to the addr and port to verify that they are available. + addr = socket.gethostbyname( self.cleaned_data['addr'] ); + port = self.cleaned_data['port']; + + try: + socktcp = socket.socket( socket.AF_INET, socket.SOCK_STREAM ); + socktcp.bind( ( addr, port ) ); + except socket.error, err: + raise forms.ValidationError( err.args[1] ); + finally: + socktcp.close(); + + try: + sockudp = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ); + sockudp.bind( ( addr, port ) ); + except socket.error, err: + raise forms.ValidationError( err.args[1] ); + finally: + sockudp.close(); + + return self.cleaned_data; class MumbleForm( ModelForm ): diff --git a/pyweb/mumble/models.py b/pyweb/mumble/models.py index dc4516d..b183004 100644 --- a/pyweb/mumble/models.py +++ b/pyweb/mumble/models.py @@ -115,12 +115,12 @@ class Mumble( models.Model ): self.srvid = self.ctl.newServer(); if self.port == -1: - self.port = max( [ mm.port for mm in Mumble.objects.all() ] ) + 1; + self.port = max( [ rec['port'] for rec in Mumble.objects.values('port') ] ) + 1; - if self.port < 0 or self.port >= 2**16: + if self.port < 1 or self.port >= 2**16: raise ValueError( _("Port number %(portno)d is not within the allowed range %(minrange)d - %(maxrange)d") % { 'portno': self.port, - 'minrange': 0, + 'minrange': 1, 'maxrange': 2**16, });