Page MenuHomePhabricator

No OneTemporary

diff --git a/config.ini.sample b/config.ini.sample
index 0e10650..b282fcd 100644
--- a/config.ini.sample
+++ b/config.ini.sample
@@ -1,70 +1,78 @@
; SylkServer configuration file
[Server]
; The following settings are the default used by the software, uncomment
; them only if you want to make changes
; default_application = conference
; Map user part of the Request URI to a specific application
; application_map = 123:conference,test:irc-conference
; trace_dir = /var/log/sylkserver
; trace_sip = False
; trace_msrp = False
; trace_notifications = False
; TLS can be used for encryption of SIP signaling and MSRP media. TLS is
; disabled by default. To enabled TLS, you must have a valid X.509
; certificate and configure it below, then set the local_tls_port in the SIP
; section and use_tls in MSRP section
; The X.509 Certificate Authorities file
; ca_file = /etc/sylkserver/tls/ca.crt
; The file containing X.509 certificate and private key in unencrypted format
; certificate = /etc/sylkserver/tls/sylkserver.crt
; verify_server = False
[SIP]
; SIP transport settings
; IP address used for SIP signaling; empty string or any means listen on interface used
; by the default route
; local_ip =
; Ports used for SIP transports, if not set to any value the transport will be disabled
; local_udp_port = 5060
; local_tcp_port = 5060
; local_tls_port =
; If set all outbound SIP requests will be sent through this SIP proxy
; outbound_proxy =
+; A comma-separated list of hosts or networks to trust.
+; The elements can be an IP address in CIDR format, a
+; hostname or an IP address (in the latter 2 a mask of 32
+; is assumed), or the special keywords 'any' and 'none'
+; (being equivalent to 0.0.0.0/0 and 0.0.0.0/32
+; respectively). It defaults to 'any'.
+; trusted_peers =
+
[MSRP]
; MSRP transport settings
; use_tls = False
[RTP]
; RTP transport settings
; Allowed codec list, valid values: G722, speex, PCMU, PCMA, iLBC, GSM
; audio_codecs = G722,speex,PCMU,PCMA
; Port range used for RTP
; port_range = 50000:50500
; SRTP valid values: disabled, mandatory, optional
; srtp_encryption = optional
; RTP stream timeout, session will be disconnected after this value
; timeout = 30
diff --git a/sylk/applications/__init__.py b/sylk/applications/__init__.py
index 8efa343..27a2a88 100644
--- a/sylk/applications/__init__.py
+++ b/sylk/applications/__init__.py
@@ -1,151 +1,224 @@
# Copyright (C) 2010-2011 AG Projects. See LICENSE for details
#
__all__ = ['ISylkApplication', 'ApplicationRegistry', 'sylk_application', 'IncomingRequestHandler']
import os
+import socket
+import struct
from application import log
+from application.configuration.datatypes import NetworkRange
from application.notification import IObserver, NotificationCenter
from application.python.util import Null, Singleton
+from itertools import chain
from sipsimple.threading import run_in_twisted_thread
from zope.interface import Attribute, Interface, implements
-from sylk.configuration import ServerConfig
+from sylk.configuration import ServerConfig, SIPConfig, ThorNodeConfig
class ISylkApplication(Interface):
"""
Interface defining attributes and methods any application must
implement.
Each application must be a Singleton and has to be decorated with
the @sylk_application decorator.
"""
__appname__ = Attribute("Application name")
def incoming_session(self, session):
pass
def incoming_subscription(self, subscribe_request, data):
pass
def incoming_referral(self, refer_request, data):
pass
def incoming_sip_message(self, message_request, data):
pass
class ApplicationRegistry(object):
__metaclass__ = Singleton
def __init__(self):
self.applications = []
def __iter__(self):
return iter(self.applications)
def add(self, app):
if app not in self.applications:
self.applications.append(app)
def sylk_application(cls):
"""Class decorator for adding applications to the ApplicationRegistry"""
ApplicationRegistry().add(cls())
return cls
def load_applications():
toplevel = os.path.dirname(__file__)
app_list = ['sylk.applications.%s' % item for item in os.listdir(toplevel) if os.path.isdir(os.path.join(toplevel, item)) and '__init__.py' in os.listdir(os.path.join(toplevel, item))]
map(__import__, app_list)
class ApplicationNotLoadedError(Exception):
pass
class IncomingRequestHandler(object):
"""
Handle incoming requests and match them to applications.
"""
__metaclass__ = Singleton
implements(IObserver)
- # TODO: apply ACLs (before or after?)
def __init__(self):
load_applications()
log.msg('Loaded applications: %s' % ', '.join([app.__appname__ for app in ApplicationRegistry()]))
self.application_map = dict((item.split(':')) for item in ServerConfig.application_map)
+ self.authorization_handler = AuthorizationHandler()
def start(self):
+ self.authorization_handler.start()
notification_center = NotificationCenter()
notification_center.add_observer(self, name='SIPSessionNewIncoming')
notification_center.add_observer(self, name='SIPIncomingSubscriptionGotSubscribe')
notification_center.add_observer(self, name='SIPIncomingReferralGotRefer')
notification_center.add_observer(self, name='SIPIncomingRequestGotRequest')
def stop(self):
+ self.authorization_handler.stop()
notification_center = NotificationCenter()
notification_center.remove_observer(self, name='SIPSessionNewIncoming')
notification_center.remove_observer(self, name='SIPIncomingSubscriptionGotSubscribe')
notification_center.remove_observer(self, name='SIPIncomingReferralGotRefer')
notification_center.remove_observer(self, name='SIPIncomingRequestGotRequest')
def get_application(self, uri):
application = self.application_map.get(uri.user, ServerConfig.default_application)
try:
app = (app for app in ApplicationRegistry() if app.__appname__ == application).next()
except StopIteration:
log.error('Application %s is not loaded' % application)
raise ApplicationNotLoadedError
else:
return app
@run_in_twisted_thread
def handle_notification(self, notification):
handler = getattr(self, '_NH_%s' % notification.name, Null)
handler(notification)
def _NH_SIPSessionNewIncoming(self, notification):
session = notification.sender
+ try:
+ self.authorization_handler.authorize_source(session.peer_address.ip)
+ except UnauthorizedRequest:
+ session.reject(403)
+ return
try:
app = self.get_application(session._invitation.request_uri)
except ApplicationNotLoadedError:
session.reject(404)
else:
app.incoming_session(session)
def _NH_SIPIncomingSubscriptionGotSubscribe(self, notification):
subscribe_request = notification.sender
+ try:
+ self.authorization_handler.authorize_source(subscribe_request.peer_address.ip)
+ except UnauthorizedRequest:
+ subscribe_request.reject(403)
+ return
try:
app = self.get_application(notification.data.request_uri)
except ApplicationNotLoadedError:
subscribe_request.reject(404)
else:
app.incoming_subscription(subscribe_request, notification.data)
def _NH_SIPIncomingReferralGotRefer(self, notification):
refer_request = notification.sender
+ try:
+ self.authorization_handler.authorize_source(refer_request.peer_address.ip)
+ except UnauthorizedRequest:
+ refer_request.reject(403)
+ return
try:
app = self.get_application(notification.data.request_uri)
except ApplicationNotLoadedError:
refer_request.reject(404)
else:
app.incoming_referral(refer_request, notification.data)
def _NH_SIPIncomingRequestGotRequest(self, notification):
request = notification.sender
if notification.data.method != 'MESSAGE':
request.answer(405)
return
+ try:
+ self.authorization_handler.authorize_source(request.peer_address.ip)
+ except UnauthorizedRequest:
+ request.answer(403)
+ return
try:
app = self.get_application(notification.data.request_uri)
except ApplicationNotLoadedError:
request.answer(404)
else:
app.incoming_sip_message(request, notification.data)
+class UnauthorizedRequest(Exception):
+ pass
+
+class AuthorizationHandler(object):
+ implements(IObserver)
+
+ def __init__(self):
+ self.state = None
+ self.trusted_peers = SIPConfig.trusted_peers
+ self.thor_nodes = []
+
+ @property
+ def trusted_parties(self):
+ if ThorNodeConfig.enabled:
+ return self.thor_nodes
+ return self.trusted_peers
+
+ def start(self):
+ notification_center = NotificationCenter()
+ notification_center.add_observer(self, name='ThorNetworkGotUpdate')
+ self.state = 'started'
+
+ def stop(self):
+ self.state = 'stopped'
+ notification_center = NotificationCenter()
+ notification_center.remove_observer(self, name='ThorNetworkGotUpdate')
+
+ def authorize_source(self, ip_address):
+ if self.state != 'started':
+ raise UnauthorizedRequest
+ for range in self.trusted_parties:
+ if struct.unpack('!L', socket.inet_aton(ip_address))[0] & range[1] == range[0]:
+ return True
+ raise UnauthorizedRequest
+
+ @run_in_twisted_thread
+ def handle_notification(self, notification):
+ handler = getattr(self, '_NH_%s' % notification.name, Null)
+ handler(notification)
+
+ def _NH_ThorNetworkGotUpdate(self, notification):
+ thor_nodes = []
+ for node in chain(*(n.nodes for n in notification.data.networks.values())):
+ thor_nodes.append(NetworkRange(node))
+ self.thor_nodes = thor_nodes
+
+
diff --git a/sylk/configuration/__init__.py b/sylk/configuration/__init__.py
index 8d3d80e..d175e93 100644
--- a/sylk/configuration/__init__.py
+++ b/sylk/configuration/__init__.py
@@ -1,68 +1,69 @@
# Copyright (C) 2010-2011 AG Projects. See LICENSE for details.
#
from application.configuration import ConfigSection, ConfigSetting
-from application.configuration.datatypes import StringList
+from application.configuration.datatypes import NetworkRangeList, StringList
from application.system import host
from sipsimple.configuration.datatypes import NonNegativeInteger, SRTPEncryption
from sylk import configuration_filename
from sylk.configuration.datatypes import AudioCodecs, IPAddress, Port, PortRange, SIPProxyAddress
from sylk.tls import Certificate, PrivateKey
class ServerConfig(ConfigSection):
__cfgfile__ = configuration_filename
__section__ = 'Server'
ca_file = ConfigSetting(type=str, value='/etc/sylkserver/tls/ca.crt')
certificate = ConfigSetting(type=str, value='/etc/sylkserver/tls/sylkserver.crt')
verify_server = False
default_application = 'conference'
application_map = ConfigSetting(type=StringList, value='')
trace_dir = ConfigSetting(type=str, value='/var/log/sylkserver')
trace_sip = False
trace_msrp = False
trace_notifications = False
class SIPConfig(ConfigSection):
__cfgfile__ = configuration_filename
__section__ = 'SIP'
local_ip = ConfigSetting(type=IPAddress, value=host.default_ip)
local_udp_port = ConfigSetting(type=Port, value=5060)
local_tcp_port = ConfigSetting(type=Port, value=5060)
local_tls_port = ConfigSetting(type=Port, value=None)
outbound_proxy = ConfigSetting(type=SIPProxyAddress, value=None)
+ trusted_peers = ConfigSetting(type=NetworkRangeList, value=NetworkRangeList('any'))
class MSRPConfig(ConfigSection):
__cfgfile__ = configuration_filename
__section__ = 'MSRP'
use_tls = False
class RTPConfig(ConfigSection):
__cfgfile__ = configuration_filename
__section__ = 'RTP'
audio_codecs = ConfigSetting(type=AudioCodecs, value=None)
port_range = ConfigSetting(type=PortRange, value=PortRange('50000:50500'))
srtp_encryption = ConfigSetting(type=SRTPEncryption, value='optional')
timeout = ConfigSetting(type=NonNegativeInteger, value=30)
class ThorNodeConfig(ConfigSection):
__cfgfile__ = configuration_filename
__section__ = 'ThorNetwork'
enabled = False
domain = "sipthor.net"
multiply = 1000
certificate = ConfigSetting(type=Certificate, value=None)
private_key = ConfigSetting(type=PrivateKey, value=None)
ca = ConfigSetting(type=Certificate, value=None)

File Metadata

Mime Type
text/x-diff
Expires
Sat, Feb 1, 11:30 AM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3489302
Default Alt Text
(12 KB)

Event Timeline