radiusserver.java

来自「TinyRadius is a simple, small and fast J」· Java 代码 · 共 545 行 · 第 1/2 页

JAVA
545
字号
	 */
	protected void listenAuth()
	throws SocketException {
		listen(getAuthSocket());
	}
		
	/**
	 * Listens on the acct port (blocks the current thread).
	 * Returns when stop() is called.
	 * @throws SocketException
	 * @throws InterruptedException
	 */
	protected void listenAcct()
	throws SocketException {
		listen(getAcctSocket());
	}

	/**
	 * Listens on the passed socket, blocks until stop() is called.
	 * @param s socket to listen on
	 */
	protected void listen(DatagramSocket s) {
		DatagramPacket packetIn = new DatagramPacket(new byte[RadiusPacket.MAX_PACKET_LENGTH], RadiusPacket.MAX_PACKET_LENGTH);
		while (true) {
			try {
				// receive packet
				try {
					logger.trace("about to call socket.receive()");
					s.receive(packetIn);
					if (logger.isDebugEnabled())
						logger.debug("receive buffer size = " + s.getReceiveBufferSize());
				} catch (SocketException se) {
					if (closing) {
						// end thread
						logger.info("got closing signal - end listen thread");
						return;
					} else {
						// retry s.receive()
						logger.error("SocketException during s.receive() -> retry", se);
						continue;
					}
				}
								
				// check client
				InetSocketAddress localAddress = (InetSocketAddress)s.getLocalSocketAddress();
				InetSocketAddress remoteAddress = new InetSocketAddress(packetIn.getAddress(), packetIn.getPort());				
				String secret = getSharedSecret(remoteAddress);
				if (secret == null) {
					if (logger.isInfoEnabled())
						logger.info("ignoring packet from unknown client " + remoteAddress + " received on local address " + localAddress);
					continue;
				}
				
				// parse packet
				RadiusPacket request = makeRadiusPacket(packetIn, secret);
				if (logger.isInfoEnabled())
					logger.info("received packet from " + remoteAddress + " on local address " + localAddress + ": " + request);

				// handle packet
				logger.trace("about to call RadiusServer.handlePacket()");
				RadiusPacket response = handlePacket(localAddress, remoteAddress, request, secret);
				
				// send response
				if (response != null) {
					if (logger.isInfoEnabled())
						logger.info("send response: " + response);
					DatagramPacket packetOut = makeDatagramPacket(response, secret, remoteAddress.getAddress(), packetIn.getPort(), request);
					s.send(packetOut);
				} else
					logger.info("no response sent");						
			} catch (SocketTimeoutException ste) {
				// this is expected behaviour
				logger.trace("normal socket timeout");
			} catch (IOException ioe) {
				// error while reading/writing socket
				logger.error("communication error", ioe);
			} catch (RadiusException re) {
				// malformed packet
				logger.error("malformed Radius packet", re);
			}
		}
	}

	/**
	 * Handles the received Radius packet and constructs a response. 
	 * @param localAddress local address the packet was received on
	 * @param remoteAddress remote address the packet was sent by
	 * @param request the packet
	 * @return response packet or null for no response
	 * @throws RadiusException
	 */
	protected RadiusPacket handlePacket(InetSocketAddress localAddress, InetSocketAddress remoteAddress, RadiusPacket request, String sharedSecret) 
	throws RadiusException, IOException {
		RadiusPacket response = null;
		
		// check for duplicates
		if (!isPacketDuplicate(request, remoteAddress)) {
			if (localAddress.getPort() == getAuthPort()) {
				// handle packets on auth port
				if (request instanceof AccessRequest)
					response = accessRequestReceived((AccessRequest)request, remoteAddress);
				else
					logger.error("unknown Radius packet type: " + request.getPacketType());
			} else if (localAddress.getPort() == getAcctPort()) {
				// handle packets on acct port
				if (request instanceof AccountingRequest)
					response = accountingRequestReceived((AccountingRequest)request, remoteAddress);
				else
					logger.error("unknown Radius packet type: " + request.getPacketType());
			} else {
				// ignore packet on unknown port
			}
		} else
			logger.info("ignore duplicate packet");

		return response;
	}

	/**
	 * Returns a socket bound to the auth port.
	 * @return socket
	 * @throws SocketException
	 */
	protected DatagramSocket getAuthSocket() 
	throws SocketException {
		if (authSocket == null) {
			if (getListenAddress() == null)
				authSocket = new DatagramSocket(getAuthPort());
			else
				authSocket = new DatagramSocket(getAuthPort(), getListenAddress());
			authSocket.setSoTimeout(getSocketTimeout());
		}
		return authSocket;
	}

	/**
	 * Returns a socket bound to the acct port.
	 * @return socket
	 * @throws SocketException
	 */
	protected DatagramSocket getAcctSocket() 
	throws SocketException {
		if (acctSocket == null) {
			if (getListenAddress() == null)
				acctSocket = new DatagramSocket(getAcctPort());
			else
				acctSocket = new DatagramSocket(getAcctPort(), getListenAddress());
			acctSocket.setSoTimeout(getSocketTimeout());
		}
		return acctSocket;
	}

	/**
	 * Creates a Radius response datagram packet from a RadiusPacket to be send. 
	 * @param packet RadiusPacket
	 * @param secret shared secret to encode packet
	 * @param address where to send the packet
	 * @param port destination port
	 * @param request request packet
	 * @return new datagram packet
	 * @throws IOException
	 */
	protected DatagramPacket makeDatagramPacket(RadiusPacket packet, String secret, InetAddress address, int port,
			RadiusPacket request) 
	throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		packet.encodeResponsePacket(bos, secret, request);
		byte[] data = bos.toByteArray();
	
		DatagramPacket datagram = new DatagramPacket(data, data.length, address, port);
		return datagram;
	}
	
	/**
	 * Creates a RadiusPacket for a Radius request from a received
	 * datagram packet.
	 * @param packet received datagram
	 * @return RadiusPacket object
	 * @exception RadiusException malformed packet
	 * @exception IOException communication error (after getRetryCount()
	 * retries)
	 */
	protected RadiusPacket makeRadiusPacket(DatagramPacket packet, String sharedSecret) 
	throws IOException, RadiusException {
		ByteArrayInputStream in = new ByteArrayInputStream(packet.getData());
		return RadiusPacket.decodeRequestPacket(in, sharedSecret);
	}
	
	/**
	 * Checks whether the passed packet is a duplicate.
	 * A packet is duplicate if another packet with the same identifier
	 * has been sent from the same host in the last time. 
	 * @param packet packet in question
	 * @param address client address
	 * @return true if it is duplicate
	 */
	protected boolean isPacketDuplicate(RadiusPacket packet, InetSocketAddress address) {
		long now = System.currentTimeMillis();
		long intervalStart = now - getDuplicateInterval();
		
		byte[] authenticator = packet.getAuthenticator();
		
		for (Iterator i = receivedPackets.iterator(); i.hasNext();) {
			ReceivedPacket p = (ReceivedPacket)i.next();
			if (p.receiveTime < intervalStart) {
				// packet is older than duplicate interval
				i.remove();
			} else {
				if (p.address.equals(address) && p.packetIdentifier == packet.getPacketIdentifier()) {
					if (authenticator != null && p.authenticator != null) {
						// packet is duplicate if stored authenticator is equal
						// to the packet authenticator
						return Arrays.equals(p.authenticator, authenticator);
					} else {
						// should not happen, packet is duplicate
						return true;
					}
				}
			}
		}
		
		// add packet to receive list
		ReceivedPacket rp = new ReceivedPacket();
		rp.address = address;
		rp.packetIdentifier = packet.getPacketIdentifier();
		rp.receiveTime = now;
		rp.authenticator = authenticator;
		receivedPackets.add(rp);
		return false;
	}

	private InetAddress listenAddress = null;
	private int authPort = 1812;
	private int acctPort = 1813;
	private DatagramSocket authSocket = null;
	private DatagramSocket acctSocket = null;
	private int socketTimeout = 3000;
	private List receivedPackets = new LinkedList();
	private long duplicateInterval = 30000; // 30 s
	private boolean closing = false;
	private static Log logger = LogFactory.getLog(RadiusServer.class);
	
}

/**
 * This internal class represents a packet that has been received by 
 * the server.
 */
class ReceivedPacket {
	
	/**
	 * The identifier of the packet.
	 */
	public int packetIdentifier;
	
	/**
	 * The time the packet was received.
	 */
	public long receiveTime;
	
	/**
	 * The address of the host who sent the packet.
	 */
	public InetSocketAddress address;
	
	/**
	 * Authenticator of the received packet.
	 */
	public byte[] authenticator;
	
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?