Source code for pyrad.proxy

# proxy.py
#
# Copyright 2005,2007 Wichert Akkerman <wichert@wiggy.net>
#
# A RADIUS proxy as defined in RFC 2865

from pyrad.server import ServerPacketError
from pyrad.server import Server
from pyrad.server import _LookupHost
from pyrad import packet
import select
import socket

# codes of the RADIUS replies accepted on the proxy socket
_REPLY_CODES = (packet.AccessAccept, packet.AccessReject,
                packet.AccountingResponse, packet.AccessChallenge,
                packet.DisconnectACK, packet.DisconnectNAK,
                packet.CoAACK, packet.CoANAK)


[docs] class Proxy(Server): """Base class for RADIUS proxies. A :class:`~pyrad.server.Server` with an extra socket, ``self._proxyfd``, to forward requests to home servers and receive their replies. :meth:`~pyrad.server.Server.Run` creates the socket (IPv4 only, not bound to a fixed port) before it starts waiting for packets. To proxy requests, override the packet handlers of :class:`~pyrad.server.Server` to forward a request: create a request for the home server, remember it together with the client request, and send it with ``self._proxyfd.sendto(request.RequestPacket(), (address, port))``. Override :meth:`_HandleProxyPacket` to process the replies: call the base method first, find the request by ``pkt.id``, verify the reply with :meth:`request.VerifyReply(pkt) <pyrad.packet.Packet.VerifyReply>` (the proxy doesn't verify replies itself), and answer the client. Home servers have to be in ``hosts`` with their secret; replies from other hosts are dropped (the ``'0.0.0.0'`` entry isn't used for the proxy socket). Note that a ``hosts`` entry also allows that host to send requests to the server. """ def _PrepareSockets(self): Server._PrepareSockets(self) self._proxyfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._fdmap[self._proxyfd.fileno()] = self._proxyfd self._poll.register(self._proxyfd.fileno(), (select.POLLIN | select.POLLPRI | select.POLLERR))
[docs] def _HandleProxyPacket(self, pkt): """Process a reply received on the proxy socket. The base method sets ``pkt.secret`` to the secret of the home server from ``hosts`` and raises :class:`~pyrad.server.ServerPacketError` for packets from unknown hosts and for packets which are not a reply (Access-Accept, Access-Reject, Access-Challenge, Accounting-Response, CoA-ACK, CoA-NAK, Disconnect-ACK or Disconnect-NAK). It doesn't verify the reply. Override it, call the base method first and then process the reply. To drop the packet raise :class:`~pyrad.server.ServerPacketError`: the main loop drops the packet and logs the reason. :param pkt: received reply, with ``pkt.source`` set to the address of the home server :type pkt: pyrad.packet.Packet """ remote_host = _LookupHost(self.hosts, pkt.source[0]) if remote_host is None: raise ServerPacketError('Received packet from unknown host') pkt.secret = remote_host.secret if pkt.code not in _REPLY_CODES: raise ServerPacketError('Received non-response on proxy socket')
def _ProcessInput(self, fd): """Process available data. If this packet should be dropped instead of processed a ServerPacketError exception should be raised. The main loop will drop the packet and log the reason. This function calls _HandleProxyPacket for the proxy socket and the base method for the other sockets. :param fd: socket to read packet from :type fd: socket.socket """ if fd.fileno() == self._proxyfd.fileno(): pkt = self._GrabPacket( lambda data, s=self: s.CreatePacket(packet=data), fd) self._HandleProxyPacket(pkt) else: Server._ProcessInput(self, fd)